def setUp(self): super().setUp() self.web = StubSite(MiningInfoResource(self.manager)) self.manager.wallet.unlock(b'MYPASS')
class BaseSendTokensTest(_BaseResourceTest._ResourceTest): __test__ = False def setUp(self): super().setUp() self.web = StubSite(SendTokensResource(self.manager)) self.web_mining = StubSite(MiningResource(self.manager)) self.web_balance = StubSite(BalanceResource(self.manager)) self.web_history = StubSite(HistoryResource(self.manager)) @inlineCallbacks def test_post(self): # Mining new block response_mining = yield self.web_mining.get("mining") data_mining = response_mining.json_value() block_bytes = resolve_block_bytes(block_bytes=data_mining['block_bytes']) yield self.web_mining.post("mining", {'block_bytes': base64.b64encode(block_bytes).decode('utf-8')}) add_blocks_unlock_reward(self.manager) self.reactor.advance(10) # Unlocking wallet self.manager.wallet.unlock(b"MYPASS") # Sending token to random address without input # Options yield self.web.options("wallet/send_tokens") data_json = {"outputs": [{"address": self.get_address(0), "value": 505}], "inputs": []} response = yield self.web.post("wallet/send_tokens", {'data': data_json}) data = response.json_value() self.assertTrue(data['success']) self.reactor.advance(10) # Asserting new balance response_balance = yield self.web_balance.get("wallet/balance") data_balance = response_balance.json_value() tokens_per_block = self.manager.get_tokens_issued_per_block(1) self.assertEqual(data_balance['balance'], {'available': tokens_per_block - 505, 'locked': 0}) # Getting history, so we can get the input response_history = yield self.web_history.get("wallet/history", {b'page': 1, b'count': 10}) data_history = response_history.json_value() input_hash = data_history['history'][0]['tx_id'] # Sending token to random address with input wrong amount data_json = { "outputs": [{ "address": self.get_address(0), "value": 500 }], "inputs": [{ "tx_id": input_hash, "index": 0 }] } response2 = yield self.web.post("wallet/send_tokens", {'data': data_json}) data2 = response2.json_value() self.assertFalse(data2['success']) self.reactor.advance(10) # Sending duplicate input data_json_duplicate = { "outputs": [{ "address": self.get_address(0), "value": 19000 }], "inputs": [{ "tx_id": input_hash, "index": 0 }, { "tx_id": input_hash, "index": 0 }] } response_duplicate = yield self.web.post("wallet/send_tokens", {'data': data_json_duplicate}) data_duplicate = response_duplicate.json_value() self.assertFalse(data_duplicate['success']) # Sending token to random address with input right amount data_json2 = { "outputs": [{ "address": self.get_address(0), "value": self.manager.get_tokens_issued_per_block(1) - 505 }], "inputs": [{ "tx_id": input_hash, "index": 0 }] } response3 = yield self.web.post("wallet/send_tokens", {'data': data_json2}) data3 = response3.json_value() self.assertTrue(data3['success']) # Sending token to invalid addresses data_json3 = {"outputs": [{"address": self.get_address(1), "value": 500}], "inputs": []} response_error1 = yield self.web.post("wallet/send_tokens", {'data': data_json3}) data_error1 = response_error1.json_value() self.assertFalse(data_error1['success']) data_json4 = {"outputs": [{"address": "1234", "value": 500}], "inputs": []} response_error2 = yield self.web.post("wallet/send_tokens", {'data': data_json4}) data_error2 = response_error2.json_value() self.assertFalse(data_error2['success']) # Error insuficient funds data_json5 = {"outputs": [{"address": self.get_address(0), "value": 5000000}], "inputs": []} response_error3 = yield self.web.post("wallet/send_tokens", {'data': data_json5}) data_error3 = response_error3.json_value() self.assertFalse(data_error3['success']) add_new_blocks(self.manager, 1, advance_clock=1) add_new_blocks(self.manager, 1, advance_clock=1) # XXX: adding extra block, not sure why this is needed add_blocks_unlock_reward(self.manager) # Sending token with timelock data_timelock = { "outputs": [{ "address": self.get_address(0), "value": 505, "timelock": 1542995660 }], "inputs": [] } response_timelock = yield self.web.post("wallet/send_tokens", {'data': data_timelock}) data_response_timelock = response_timelock.json_value() self.assertTrue(data_response_timelock['success']) self.reactor.advance(5) # Sending token with timestamp data_timestamp = { "outputs": [{ "address": self.get_address(0), "value": 5 }], "inputs": [], "timestamp": int(self.reactor.seconds()) } response_timestamp = yield self.web.post("wallet/send_tokens", {'data': data_timestamp}) data_response_timestamp = response_timestamp.json_value() self.assertTrue(data_response_timestamp['success']) self.reactor.advance(5) # Sending token with timestamp=0 data_timestamp = { "outputs": [{ "address": self.get_address(0), "value": 5 }], "inputs": [], "timestamp": 0 } response_timestamp = yield self.web.post("wallet/send_tokens", {'data': data_timestamp}) data_response_timestamp = response_timestamp.json_value() self.assertTrue(data_response_timestamp['success']) @inlineCallbacks def test_tx_weight(self): _set_test_mode(TestMode.DISABLED) add_new_blocks(self.manager, 3, advance_clock=1) add_blocks_unlock_reward(self.manager) self.reactor.advance(3) # Unlocking wallet self.manager.wallet.unlock(b"MYPASS") data_json = { "outputs": [{ "address": self.get_address(0), "value": 505 }], "inputs": [], "weight": 1 } response = yield self.web.post("wallet/send_tokens", {'data': data_json}) data = response.json_value() self.assertFalse(data['success']) def test_error_request(self): resource = SendTokensResource(self.manager) request = TestDummyRequest('POST', 'wallet/send_tokens', {}) self.assertIsNotNone(request._finishedDeferreds) resource._err_tx_resolve('Error', request) self.assertIsNone(request._finishedDeferreds)
class SendTokensTest(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() self.network = 'testnet' self.manager = self.create_peer(self.network, unlock_wallet=True, wallet_index=True) sendtokens_resource = SendTokensResource(self.manager) sendtokens_resource.sleep_seconds = 0.1 self.web = StubSite(sendtokens_resource) self.web_address_history = StubSite( AddressHistoryResource(self.manager)) @inlineCallbacks def test_post(self): # Unlocking wallet self.manager.wallet.unlock(b'MYPASS') blocks = add_new_blocks(self.manager, 3, advance_clock=1) add_blocks_unlock_reward(self.manager) blocks_tokens = [ sum(txout.value for txout in blk.outputs) for blk in blocks ] self.assertEqual( self.manager.wallet.balance[settings.HATHOR_TOKEN_UID].available, sum(blocks_tokens)) # Options yield self.web.options('thin_wallet/send_tokens') tx_id = blocks[0].hash output = blocks[0].outputs[0] script_type_out = parse_address_script(output.script) address = script_type_out.address private_key = self.manager.wallet.get_private_key(address) output_address = decode_address(self.get_address(0)) value = blocks_tokens[0] o = TxOutput(value, create_output_script(output_address, None)) o_invalid_amount = TxOutput(value - 1, create_output_script(output_address, None)) i = TxInput(tx_id, 0, b'') # wrong weight tx = Transaction(inputs=[i], outputs=[o]) data_to_sign = tx.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) i.data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx.inputs = [i] tx.timestamp = int(self.clock.seconds()) tx.weight = 0 response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': tx.get_struct().hex()}) data = response.json_value() self.assertFalse(data['success']) # Error wrong amount tx2 = Transaction(inputs=[i], outputs=[o_invalid_amount]) data_to_sign = tx2.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) i.data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx2.inputs = [i] tx2.timestamp = int(self.clock.seconds()) tx2.weight = self.manager.minimum_tx_weight(tx2) response_wrong_amount = yield self.web.post( 'thin_wallet/send_tokens', {'tx_hex': tx2.get_struct().hex()}) data_wrong_amount = response_wrong_amount.json_value() self.assertFalse(data_wrong_amount['success']) # successful tx tx3 = Transaction(inputs=[i], outputs=[o]) data_to_sign = tx3.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) i.data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx3.inputs = [i] tx3.timestamp = int(self.clock.seconds()) tx3.weight = self.manager.minimum_tx_weight(tx3) # Then send tokens response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': tx3.get_struct().hex()}) data = response.json_value() self.assertTrue(data['success']) # Trying to send a double spending will not have success self.clock.advance(5) tx3.timestamp = int(self.clock.seconds()) response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': tx3.get_struct().hex()}) data_error = response.json_value() self.assertFalse(data_error['success']) self.clock.advance(5) # Check if tokens were really sent self.assertEqual( self.manager.wallet.balance[settings.HATHOR_TOKEN_UID].available, sum(blocks_tokens[:-1])) response_history = yield self.web_address_history.get( 'thin_wallet/address_history', { b'addresses[]': address.encode(), }) response_data = response_history.json_value()['history'] self.assertIn(data['tx']['hash'], [x['tx_id'] for x in response_data]) # Create token tx tx4 = create_tokens(self.manager, address, mint_amount=100, propagate=False) tx4.nonce = 0 tx4.timestamp = int(self.clock.seconds()) response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': tx4.get_struct().hex()}) data = response.json_value() self.assertTrue(data['success']) # # TODO these tests were causing timeouts in CI server [yan - 01.04.2019] # TODO add to top imports # from twisted.internet.defer import CancelledError, inlineCallbacks # from twisted.python.failure import Failure # def get_new_tx_struct(weight=0): # tx = Transaction(inputs=[i], outputs=[o]) # tx.inputs = tx3.inputs # self.clock.advance(5) # tx.timestamp = int(self.clock.seconds()) # if weight == 0: # weight = self.manager.minimum_tx_weight(tx) # tx.weight = weight # return tx.get_struct().hex() # # # Making pow threads full # deferreds = [] # for x in range(settings.MAX_POW_THREADS): # d = self.web.post('thin_wallet/send_tokens', {'tx_hex': get_new_tx_struct(50)}) # d.addErrback(lambda err: None) # deferreds.append(d) # # # All threads are in use # response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': get_new_tx_struct(1)}) # data = response.json_value() # self.assertFalse(data['success']) # # # Releasing one thread # d = deferreds.pop() # d.request.processingFailed(Failure(CancelledError())) # # # Waiting for thread to finish # yield d.request.thread_deferred # # # Now you can send # response = yield self.web.post('thin_wallet/send_tokens', {'tx_hex': get_new_tx_struct(1)}) # data = response.json_value() # self.assertTrue(data['success']) # # # Releasing all other threads # for d in deferreds: # d.request.processingFailed(Failure(CancelledError())) # # # Waiting for all threads to finish # for d in deferreds: # yield d.request.thread_deferred def test_error_request(self): resource = SendTokensResource(self.manager) request = TestDummyRequest('POST', 'thin_wallet/send_tokens', {}) self.assertIsNotNone(request._finishedDeferreds) resource._err_tx_resolve('Error', request) self.assertIsNone(request._finishedDeferreds) @inlineCallbacks def test_token(self): self.manager.wallet.unlock(b'MYPASS') resource = StubSite(TokenResource(self.manager)) # test list of tokens empty response_list1 = yield resource.get('thin_wallet/token') data_list1 = response_list1.json_value() self.assertTrue(data_list1['success']) self.assertEqual(len(data_list1['tokens']), 0) # test invalid token id response = yield resource.get('thin_wallet/token', {b'id': 'vvvv'.encode()}) data = response.json_value() self.assertFalse(data['success']) # test unknown token id unknown_uid = '00000000228ed1dd74a2e1b920c1d64bf81dc63875dce4fac486001073b45a27'.encode( ) response = yield resource.get('thin_wallet/token', {b'id': unknown_uid}) data = response.json_value() self.assertFalse(data['success']) # test success case add_new_blocks(self.manager, 1, advance_clock=1) add_blocks_unlock_reward(self.manager) token_name = 'MyTestToken' token_symbol = 'MTT' amount = 150 tx = create_tokens(self.manager, mint_amount=amount, token_name=token_name, token_symbol=token_symbol, use_genesis=False) token_uid = tx.tokens[0] response = yield resource.get('thin_wallet/token', {b'id': token_uid.hex().encode()}) data = response.json_value() self.assertTrue(data['success']) self.assertEqual(len(data['mint']), 1) self.assertEqual(len(data['melt']), 1) self.assertEqual(data['mint'][0]['tx_id'], tx.hash_hex) self.assertEqual(data['melt'][0]['tx_id'], tx.hash_hex) self.assertEqual(data['mint'][0]['index'], 1) self.assertEqual(data['melt'][0]['index'], 2) self.assertEqual(data['total'], amount) self.assertEqual(data['name'], token_name) self.assertEqual(data['symbol'], token_symbol) # test list of tokens with one token response_list2 = yield resource.get('thin_wallet/token') data_list2 = response_list2.json_value() self.assertTrue(data_list2['success']) self.assertEqual(len(data_list2['tokens']), 1) self.assertEqual(data_list2['tokens'][0]['name'], token_name) self.assertEqual(data_list2['tokens'][0]['symbol'], token_symbol) self.assertEqual(data_list2['tokens'][0]['uid'], tx.hash.hex()) token_name2 = 'New Token' token_symbol2 = 'NTK' tx2 = create_tokens(self.manager, mint_amount=amount, token_name=token_name2, token_symbol=token_symbol2, use_genesis=False) token_name3 = 'Wat Coin' token_symbol3 = 'WTC' tx3 = create_tokens(self.manager, mint_amount=amount, token_name=token_name3, token_symbol=token_symbol3, use_genesis=False) # test list of tokens with 3 tokens response_list3 = yield resource.get('thin_wallet/token') data_list3 = response_list3.json_value() self.assertTrue(data_list3['success']) self.assertEqual(len(data_list3['tokens']), 3) token1 = { 'uid': tx.hash.hex(), 'name': token_name, 'symbol': token_symbol } token2 = { 'uid': tx2.hash.hex(), 'name': token_name2, 'symbol': token_symbol2 } token3 = { 'uid': tx3.hash.hex(), 'name': token_name3, 'symbol': token_symbol3 } self.assertIn(token1, data_list3['tokens']) self.assertIn(token2, data_list3['tokens']) self.assertIn(token3, data_list3['tokens']) # test no wallet index manager2 = self.create_peer(self.network, unlock_wallet=True) resource2 = StubSite(TokenResource(manager2)) response2 = yield resource2.get('thin_wallet/token') data2 = response2.json_value() self.assertEqual(response2.responseCode, 503) self.assertFalse(data2['success']) @inlineCallbacks def test_token_history(self): self.manager.wallet.unlock(b'MYPASS') resource = StubSite(TokenHistoryResource(self.manager)) add_new_blocks(self.manager, 1, advance_clock=1) add_blocks_unlock_reward(self.manager) tx = create_tokens(self.manager, mint_amount=100, token_name='Teste', token_symbol='TST') token_uid = tx.tokens[0] response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 3 }) data = response.json_value() # Success returning the token creation tx self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get('thin_wallet/token_history', { b'id': b'123', b'count': 3 }) data = response.json_value() # Fail because token is unknown self.assertFalse(data['success']) # Create a tx with this token, so we can have more tx in the history output = tx.outputs[0] script_type_out = parse_address_script(output.script) address = script_type_out.address private_key = self.manager.wallet.get_private_key(address) output_address = decode_address(self.get_address(0)) o = TxOutput(100, create_output_script(output_address, None), 1) i = TxInput(tx.hash, 0, b'') tx2 = Transaction(inputs=[i], outputs=[o], tokens=[token_uid]) data_to_sign = tx2.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) i.data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx2.inputs = [i] tx2.timestamp = int(self.clock.seconds()) tx2.weight = self.manager.minimum_tx_weight(tx2) tx2.parents = self.manager.get_new_tx_parents() tx2.resolve() self.manager.propagate_tx(tx2) # Now we have 2 txs with this token response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 3 }) data = response.json_value() # Success returning the token creation tx and newly created tx self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(2, len(data['transactions'])) self.assertEqual(tx2.hash.hex(), data['transactions'][0]['tx_id']) self.assertEqual(tx.hash.hex(), data['transactions'][1]['tx_id']) response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 1 }) data = response.json_value() # Testing has_more self.assertTrue(data['success']) self.assertTrue(data['has_more']) self.assertEqual(1, len(data['transactions'])) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 10, b'page': b'next', b'hash': tx2.hash.hex().encode(), b'timestamp': str(tx2.timestamp).encode(), }) data = response.json_value() # Testing next self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 10, b'page': b'previous', b'hash': tx.hash.hex().encode(), b'timestamp': str(tx.timestamp).encode(), }) data = response.json_value() # Testing previous self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx2.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': 10, b'page': b'previous', b'hash': tx2.hash.hex().encode(), b'timestamp': str(tx2.timestamp).encode(), }) data = response.json_value() # Testing previous from first self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(0, len(data['transactions']))
class GraphvizTest(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() resource = GraphvizLegacyResource(self.manager) resource.isLeaf = True self.web = StubSite(resource) # Unlocking wallet self.manager.wallet.unlock(b'MYPASS') # Creating blocks, txs and a conflict tx to test graphviz with it add_new_blocks(self.manager, 2, advance_clock=2) add_blocks_unlock_reward(self.manager) txs = add_new_transactions(self.manager, 2, advance_clock=2) tx = txs[0] self.tx2 = Transaction.create_from_struct(tx.get_struct()) self.tx2.parents = [tx.parents[1], tx.parents[0]] self.tx2.resolve() self.manager.propagate_tx(self.tx2) @inlineCallbacks def test_get(self): # With parameters response = yield self.web.get('graphviz', { b'format': b'dot', b'weight': b'true', b'acc_weight': b'true' }) data = response.written[0] self.assertIsNotNone(data) # Without parameters response2 = yield self.web.get('graphviz', {}) data2 = response2.written[0] self.assertIsNotNone(data2) # Funds graph without parameter response3 = yield self.web.get('graphviz', {b'funds': b'true'}) data3 = response3.written[0] self.assertIsNotNone(data3) # Funds graph with parameter response4 = yield self.web.get('graphviz', { b'funds': b'true', b'weight': b'true', b'acc_weight': b'true' }) data4 = response4.written[0] self.assertIsNotNone(data4) # Tx neighbor graph response5 = yield self.web.get( 'graphviz', { b'tx': self.tx2.hash_hex.encode('utf-8'), b'graph_type': b'funds', b'max_level': b'2' }) data5 = response5.written[0] self.assertIsNotNone(data5) # Tx neighbor error response6 = yield self.web.get( 'graphviz', { b'tx': self.tx2.hash_hex.encode('utf-8'), b'graph_type': b'funds', b'max_level': b'20' }) data6 = response6.json_value() self.assertFalse(data6['success']) def test_parse_arg(self): resource = GraphvizLegacyResource(self.manager) false_args = ['false', 'False', '0', None, 0, False] for arg in false_args: self.assertFalse(resource.parseBoolArg(arg)) true_args = ['true', 'True', '1', 1, True] for arg in true_args: self.assertTrue(resource.parseBoolArg(arg)) def test_error_request(self): resource = GraphvizLegacyResource(self.manager) request = TestDummyRequest('GET', 'graphviz', {}) self.assertIsNotNone(request._finishedDeferreds) resource._err_tx_resolve('Error', request) self.assertIsNone(request._finishedDeferreds)
def setUp(self): super().setUp() self.web = StubSite(MiningResource(self.manager))
def setUp(self): super().setUp() self.web = StubSite(UnlockWalletResource(self.manager)) self.web_lock = StubSite(LockWalletResource(self.manager)) self.web_state = StubSite(StateWalletResource(self.manager))
class StratumResourceTest(_BaseResourceTest._ResourceTest): def _manager_kwargs(self): kwargs = super()._manager_kwargs() kwargs['stratum_port'] = 8123 return kwargs def setUp(self): super().setUp() self.web = StubSite(MiningStatsResource(self.manager)) @skip('broken') @inlineCallbacks def test_get(self): response = yield self.web.get('miners') data = response.json_value() self.assertEqual(data, []) @skip('broken') @inlineCallbacks def test_subscribe_and_mine(self): import json from hashlib import sha256 # boilerplate needed to exchange bytes transport = StringTransportWithDisconnection() protocol = self.manager.stratum_factory.buildProtocol(IPv4Address('TCP', '127.0.0.1', 8123)) transport.protocol = protocol protocol.makeConnection(transport) # subscribe req = { 'jsonrpc': '2.0', 'id': '1', 'method': 'subscribe' } protocol.lineReceived(json.dumps(req).encode()) res = transport.value().split(JSONRPC.delimiter) self.assertEqual(len(res), 3) # check if we have subscribed response = yield self.web.get('miners') data = response.json_value() self.assertIsInstance(data, list) self.assertEqual(len(data), 1) res = data[0] del res['connection_start_time'] del res['miner_id'] self.assertEqual( res, {'address': '127.0.0.1:8123', 'blocks_found': 0, 'completed_jobs': 0, 'estimated_hash_rate': 0.0} ) # mine a block # TODO: use predictable work instead of always repeating this work job = json.loads(res[1])['params'] job_id = job['job_id'] job_hash1 = sha256(bytes.fromhex(job['data'])) job_nonce_size = job['nonce_size'] job_max_nonce = 1 << (8 * job_nonce_size) job_target = 2**(256 - job['weight']) - 1 nonce = 0 while nonce < job_max_nonce: job_hash2 = job_hash1.copy() job_hash2.update(nonce.to_bytes(job_nonce_size, 'big')) if int(sha256(job_hash2.digest()).digest()[::-1].hex(), 16) < job_target: break nonce += 1 # FIXME: assuming nonce was found: exited loop through break # submit our work req = {'job_id': job_id, 'nonce': nonce} protocol.lineReceived(json.dumps(req).encode()) res = transport.value().split(JSONRPC.delimiter) self.assertEqual(len(res), 4) self.assertTrue(False) # check if our work has updated the stats response = yield self.web.get('miners') data = response.json_value() self.assertIsInstance(data, list) self.assertEqual(len(data), 1) res = data[0] del res['connection_start_time'] del res['miner_id'] self.assertEqual( res, # TODO: what is the actual estimated hash rate? should we test it? {'address': '127.0.0.1:8123', 'blocks_found': 1, 'completed_jobs': 1, 'estimated_hash_rate': 0.0} )
class BaseTransactionTest(_BaseResourceTest._ResourceTest): __test__ = False def setUp(self): super().setUp() self.web = StubSite(CreateTxResource(self.manager)) self.manager.wallet.unlock(b'MYPASS') self.spent_blocks = add_new_blocks(self.manager, 10) self.unspent_blocks = add_blocks_unlock_reward(self.manager) add_blocks_unlock_reward(self.manager) self.unspent_address = self.manager.wallet.get_unused_address() self.unspent_tx = add_new_tx(self.manager, self.unspent_address, 100) self.unspent_tx2 = add_new_tx(self.manager, self.unspent_address, 200) self.unspent_tx3 = add_new_tx(self.manager, self.unspent_address, 300) add_blocks_unlock_reward(self.manager) # Example from the design: # # POST request body: # # { # "inputs": [ # { # "tx_id": "000005551d7740fd7d3c0acc50b5677fdd844f1225985aa431e1712af2a2fd89", # "index": 1 # } # ], # "outputs": [ # { # "address": "HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A", # "value": 5600 # } # ] # } # # POST response body: # # { # "success": true, # "hex_data": "0001000101000005551d7740fd7d3c0acc50b5677fdd844f1225985aa431e171\ # 2af2a2fd89010000000015e000001976a914afa600556bf43ece9b8e0486baa31\ # bd46a82c3af88ac40310c373eed982e5f63d94d0200000000b0e8be665f308f1d\ # 48d2201060846203280062b1cccc4e3d657486e90000000071c0d2cafa192b421\ # bb5727c84174c999f9400d3be74331e7feba08a00000000", # "data": { # "timestamp": 1600379213, # "version": 1, # "weight": 17.047717984205683, # "parents": [ # "00000000b0e8be665f308f1d48d2201060846203280062b1cccc4e3d657486e9", # "0000000071c0d2cafa192b421bb5727c84174c999f9400d3be74331e7feba08a" # ], # "inputs": [ # { # "tx_id": "000005551d7740fd7d3c0acc50b5677fdd844f1225985aa431e1712af2a2fd89", # "index": 1, # "data": "" # } # ], # "outputs": [ # { # "value": 5600, # "token_data": 0, # "script": "dqkUr6YAVWv0Ps6bjgSGuqMb1GqCw6+IrA==" # } # ], # "tokens": [] # } # } @inlineCallbacks def test_spend_block(self): block = self.unspent_blocks[0] address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' script = create_base_script(address).get_script() resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': block.hash_hex, 'index': 0, }], 'outputs': [{ 'address': address, 'value': 6400, }] })).json_value() self.assertEqual(resp['success'], True) data = resp['data'] hex_data = resp['hex_data'] struct_bytes = bytes.fromhex(hex_data) tx = Transaction.create_from_struct(struct_bytes) tx_data = tx.to_json() del tx_data['hash'] del tx_data['nonce'] self.assertEqual(data, tx_data) self.assertEqual(len(tx.inputs), 1) self.assertEqual(tx.inputs[0].tx_id, block.hash) self.assertEqual(tx.inputs[0].index, 0) self.assertEqual(tx.inputs[0].data, b'') self.assertEqual(len(tx.outputs), 1) self.assertEqual(tx.outputs[0].value, 6400) self.assertEqual(tx.outputs[0].token_data, 0) self.assertEqual(tx.outputs[0].script, script) @inlineCallbacks def test_spend_tx(self): src_tx = self.unspent_tx address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' script = create_base_script(address).get_script() resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': src_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'address': address, 'value': 100, }] })).json_value() self.assertEqual(resp['success'], True) data = resp['data'] hex_data = resp['hex_data'] struct_bytes = bytes.fromhex(hex_data) tx = Transaction.create_from_struct(struct_bytes) tx_data = tx.to_json() del tx_data['hash'] del tx_data['nonce'] self.assertEqual(data, tx_data) self.assertEqual(len(tx.inputs), 1) self.assertEqual(tx.inputs[0].tx_id, src_tx.hash) self.assertEqual(tx.inputs[0].index, 1) self.assertEqual(tx.inputs[0].data, b'') self.assertEqual(len(tx.outputs), 1) self.assertEqual(tx.outputs[0].value, 100) self.assertEqual(tx.outputs[0].token_data, 0) self.assertEqual(tx.outputs[0].script, script) @inlineCallbacks def test_spend_tx_by_script(self): src_tx = self.unspent_tx address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' script = create_base_script(address).get_script() script_str = base64.b64encode(script).decode('utf-8') resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': src_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'script': script_str, 'value': 100, }] })).json_value() self.assertEqual(resp['success'], True) data = resp['data'] hex_data = resp['hex_data'] struct_bytes = bytes.fromhex(hex_data) tx = Transaction.create_from_struct(struct_bytes) tx_data = tx.to_json() del tx_data['hash'] del tx_data['nonce'] self.assertEqual(data, tx_data) self.assertEqual(len(tx.inputs), 1) self.assertEqual(tx.inputs[0].tx_id, src_tx.hash) self.assertEqual(tx.inputs[0].index, 1) self.assertEqual(tx.inputs[0].data, b'') self.assertEqual(len(tx.outputs), 1) self.assertEqual(tx.outputs[0].value, 100) self.assertEqual(tx.outputs[0].token_data, 0) self.assertEqual(tx.outputs[0].script, script) @inlineCallbacks def test_tx_propagate(self): _set_test_mode( TestMode.DISABLED) # disable test_mode so the weight is not 1 src_tx = self.unspent_tx output_address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': src_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'address': output_address, 'value': 100, }] })).json_value() self.assertEqual(resp['success'], True) data = resp['data'] hex_data = resp['hex_data'] struct_bytes = bytes.fromhex(hex_data) orig_tx = Transaction.create_from_struct(struct_bytes) tx = orig_tx.clone() tx_data = tx.to_json() del tx_data['hash'] del tx_data['nonce'] self.assertEqual(data, tx_data) data_to_sign = tx.get_sighash_all() private_key = self.manager.wallet.get_private_key(self.unspent_address) public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) input_data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx.inputs[0].data = input_data # XXX: tx.resolve is a bit CPU intensive, but not so much as to make this test disabled by default tx.resolve(False) self.assertTrue(self.manager.propagate_tx(tx)) @inlineCallbacks def test_tx_propagate_multiple_inputs(self): _set_test_mode( TestMode.DISABLED) # disable test_mode so the weight is not 1 output_address = 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' resp = (yield self.web.post( 'create_tx', { 'inputs': [ { 'tx_id': self.unspent_tx.hash_hex, 'index': 1, }, { 'tx_id': self.unspent_tx2.hash_hex, 'index': 1, }, { 'tx_id': self.unspent_tx3.hash_hex, 'index': 1, }, ], 'outputs': [ { 'address': output_address, 'value': 600, }, ] })).json_value() self.assertEqual(resp['success'], True) data = resp['data'] hex_data = resp['hex_data'] struct_bytes = bytes.fromhex(hex_data) orig_tx = Transaction.create_from_struct(struct_bytes) tx = orig_tx.clone() tx_data = tx.to_json() del tx_data['hash'] del tx_data['nonce'] self.assertEqual(data, tx_data) data_to_sign = tx.get_sighash_all() private_key = self.manager.wallet.get_private_key(self.unspent_address) public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) input_data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx.inputs[0].data = input_data tx.inputs[1].data = input_data tx.inputs[2].data = input_data # XXX: tx.resolve is a bit CPU intensive, but not so much as to make this test disabled by default tx.resolve(False) self.assertTrue(self.manager.propagate_tx(tx)) @inlineCallbacks def test_already_spent(self): block = self.spent_blocks[0] resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': block.hash_hex, 'index': 0, }], 'outputs': [{ 'address': 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A', 'value': 6400, }] })).json_value() self.assertEqual( resp, { 'error': 'At least one of your inputs has already been spent.', }) @inlineCallbacks def test_invalid_value(self): resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': self.unspent_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'address': 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A', 'value': 101, }] })).json_value() self.assertEqual( resp, { 'error': 'HTR balance is different than expected. (amount=1, expected=0)' }) @inlineCallbacks def test_invalid_value2(self): resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': self.unspent_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'address': 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A', 'value': 99, }] })).json_value() self.assertEqual( resp, { 'error': 'HTR balance is different than expected. (amount=-1, expected=0)' }) @inlineCallbacks def test_invalid_address(self): resp = (yield self.web.post( 'create_tx', { 'inputs': [{ 'tx_id': self.unspent_tx.hash_hex, 'index': 1, }], 'outputs': [{ 'address': 'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199Aa', 'value': 99, }] })).json_value() self.assertEqual(resp, {'error': 'Address size must have 25 bytes'})
class BaseTransactionTest(_BaseResourceTest._ResourceTest): __test__ = False def setUp(self): super().setUp() self.web = StubSite(ValidateAddressResource(self.manager)) # Example from the design: # # ❯ curl localhost:9080/v1a/validate_address/HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A -s | jq # { # "valid": true, # "script": "dqkUr6YAVWv0Ps6bjgSGuqMb1GqCw6+IrA==", # "address": "HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A", # "type": "p2pkh" # } @inlineCallbacks def test_simple(self): address = b'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199A' response_success = yield self.web.get(address) data_success = response_success.json_value() self.assertEqual( data_success, { 'valid': True, 'script': 'dqkUr6YAVWv0Ps6bjgSGuqMb1GqCw6+IrA==', 'address': address.decode('ascii'), 'type': 'p2pkh', }) @inlineCallbacks def test_invalid_network(self): # this address is valid on the testnet response_success = yield self.web.get( b'WTPcVyGjo9tSet8QAH7qudW2LwtkgubZGU') data_success = response_success.json_value() self.assertEqual( data_success, { 'valid': False, 'error': 'ScriptError', 'msg': 'The address is not valid', }) @inlineCallbacks def test_wrong_size(self): address = b'HNXsVtRUmwDCtpcCJUrH4QiHo9kUKx199Aa' response_success = yield self.web.get(address) data_success = response_success.json_value() self.assertEqual( data_success, { 'valid': False, 'error': 'InvalidAddress', 'msg': 'Address size must have 25 bytes', }) @inlineCallbacks def test_gibberish(self): # this isn't remotely what an address looks like response_success = yield self.web.get(b'ahl8sfyoiuh23$%!!dfads') data_success = response_success.json_value() self.assertEqual( data_success, { 'valid': False, 'error': 'InvalidAddress', 'msg': 'Invalid base58 address', })
class TransactionTest(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() self.web = StubSite(TransactionResource(self.manager)) self.manager.wallet.unlock(b'MYPASS') @inlineCallbacks def test_get_one(self): genesis_tx = next(x for x in self.manager.tx_storage.get_all_genesis() if x.is_block) response_success = yield self.web.get( "transaction", {b'id': bytes(genesis_tx.hash.hex(), 'utf-8')}) data_success = response_success.json_value() self.assertTrue(data_success['success']) dict_test = genesis_tx.to_json(decode_script=True) dict_test['raw'] = genesis_tx.get_struct().hex() dict_test['nonce'] = str(dict_test['nonce']) if genesis_tx.is_block: dict_test['height'] = genesis_tx.calculate_height() self.assertEqual(data_success['tx'], dict_test) # Test sending hash that does not exist response_error1 = yield self.web.get( "transaction", { b'id': b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a5533848' }) data_error1 = response_error1.json_value() self.assertFalse(data_error1['success']) # Test sending invalid hash response_error2 = yield self.web.get( "transaction", { b'id': b'000000831cff82fa730cbdf8640fae6c130aab1681336e2f8574e314a553384' }) data_error2 = response_error2.json_value() self.assertFalse(data_error2['success']) # Adding blocks to have funds add_new_blocks(self.manager, 2, advance_clock=1) add_blocks_unlock_reward(self.manager) tx = add_new_transactions(self.manager, 1)[0] tx2 = Transaction.create_from_struct(tx.get_struct()) tx2.parents = [tx.parents[1], tx.parents[0]] tx2.resolve() self.manager.propagate_tx(tx2) # Now we get a tx with conflict, voided_by and twin response_conflict = yield self.web.get( "transaction", {b'id': bytes(tx2.hash.hex(), 'utf-8')}) data_conflict = response_conflict.json_value() self.assertTrue(data_conflict['success']) @inlineCallbacks def test_get_many(self): # Add some blocks and txs and get them in timestamp order blocks = add_new_blocks(self.manager, 4, advance_clock=1) _blocks = add_blocks_unlock_reward(self.manager) txs = sorted(add_new_transactions(self.manager, 25), key=lambda x: (x.timestamp, x.hash)) blocks.extend(_blocks) blocks = sorted(blocks, key=lambda x: (x.timestamp, x.hash)) # Get last 2 blocks expected1 = blocks[-2:] expected1.reverse() response1 = yield self.web.get("transaction", { b'count': b'2', b'type': b'block' }) data1 = response1.json_value() for expected, result in zip(expected1, data1['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertTrue(data1['has_more']) # Get last 8 txs expected2 = txs[-8:] expected2.reverse() response2 = yield self.web.get("transaction", { b'count': b'8', b'type': b'tx' }) data2 = response2.json_value() for expected, result in zip(expected2, data2['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertTrue(data2['has_more']) # Get older blocks with hash reference expected3 = blocks[:2] expected3.reverse() response3 = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'timestamp': bytes(str(blocks[2].timestamp), 'utf-8'), b'hash': bytes(blocks[2].hash.hex(), 'utf-8'), b'page': b'next' }) data3 = response3.json_value() for expected, result in zip(expected3, data3['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertFalse(data3['has_more']) # Get newer txs with hash reference response4 = yield self.web.get( "transaction", { b'count': b'16', b'type': b'tx', b'timestamp': bytes(str(txs[-9].timestamp), 'utf-8'), b'hash': bytes(txs[-9].hash.hex(), 'utf-8'), b'page': b'previous' }) data4 = response4.json_value() for expected, result in zip(expected2, data4['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertFalse(data4['has_more']) # Get newer blocks with hash reference expected5 = blocks[-2:] expected5.reverse() response5 = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'timestamp': bytes(str(expected1[-1].timestamp), 'utf-8'), b'hash': bytes(expected1[-1].hash.hex(), 'utf-8'), b'page': b'previous' }) data5 = response5.json_value() for expected, result in zip(expected5, data5['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertFalse(data5['has_more']) # Get txs with hash reference expected6 = txs[:8] expected6.reverse() response6 = yield self.web.get( "transaction", { b'count': b'8', b'type': b'tx', b'timestamp': bytes(str(txs[8].timestamp), 'utf-8'), b'hash': bytes(txs[8].hash.hex(), 'utf-8'), b'page': b'next' }) data6 = response6.json_value() for expected, result in zip(expected6, data6['transactions']): self.assertEqual(expected.timestamp, result['timestamp']) self.assertEqual(expected.hash.hex(), result['tx_id']) self.assertTrue(data6['has_more']) @inlineCallbacks def test_invalid_params(self): # Add some blocks and txs add_new_blocks(self.manager, 4, advance_clock=1) add_blocks_unlock_reward(self.manager) add_new_transactions(self.manager, 3) # invalid count response = yield self.web.get("transaction", { b'count': b'a', b'type': b'block' }) data = response.json_value() self.assertFalse(data['success']) # missing type response = yield self.web.get("transaction", {b'count': b'3'}) data = response.json_value() self.assertFalse(data['success']) # invalid type response = yield self.web.get("transaction", { b'count': b'3', b'type': b'block1' }) data = response.json_value() self.assertFalse(data['success']) # missing timestamp response = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'hash': bytes( '0000000043bae7193ae512e8e6e6cd666ef3ea46db6df63bd22f201c5fd682ea', 'utf-8') }) data = response.json_value() self.assertFalse(data['success']) # invalid timestamp response = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'hash': bytes( '0000000043bae7193ae512e8e6e6cd666ef3ea46db6df63bd22f201c5fd682ea', 'utf-8'), b'timestamp': b'aa' }) data = response.json_value() self.assertFalse(data['success']) # missing page response = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'hash': bytes( '0000000043bae7193ae512e8e6e6cd666ef3ea46db6df63bd22f201c5fd682ea', 'utf-8'), b'timestamp': b'1579716659' }) data = response.json_value() self.assertFalse(data['success']) # invalid timestamp response = yield self.web.get( "transaction", { b'count': b'3', b'type': b'block', b'hash': bytes( '0000000043bae7193ae512e8e6e6cd666ef3ea46db6df63bd22f201c5fd682ea', 'utf-8'), b'timestamp': b'1579716659', b'page': b'next1' }) data = response.json_value() self.assertFalse(data['success'])
def setUp(self): super().setUp() self.web = StubSite(AddPeersResource(self.manager))
def setUp(self): super().setUp() self.web = StubSite(DashboardTransactionResource(self.manager))
def setUp(self): super().setUp() self.web = StubSite(StatusResource(self.manager)) self.manager2 = self.create_peer('testnet') self.conn1 = FakeConnection(self.manager, self.manager2)
class BaseStatusTest(_BaseResourceTest._ResourceTest): __test__ = False def setUp(self): super().setUp() self.web = StubSite(StatusResource(self.manager)) self.manager2 = self.create_peer('testnet') self.conn1 = FakeConnection(self.manager, self.manager2) @inlineCallbacks def test_get(self): response = yield self.web.get("status") data = response.json_value() server_data = data.get('server') self.assertEqual(server_data['app_version'], 'Hathor v{}'.format(hathor.__version__)) self.assertEqual(server_data['network'], 'testnet') self.assertGreater(server_data['uptime'], 0) @inlineCallbacks def test_handshaking(self): response = yield self.web.get("status") data = response.json_value() server_data = data.get('server') known_peers = data.get('known_peers') connections = data.get('connections') self.assertEqual(server_data['app_version'], 'Hathor v{}'.format(hathor.__version__)) self.assertEqual(server_data['network'], 'testnet') self.assertGreater(server_data['uptime'], 0) handshake_peer = self.conn1.proto1.transport.getPeer() handshake_address = '{}:{}'.format(handshake_peer.host, handshake_peer.port) self.assertEqual(len(known_peers), 0) self.assertEqual(len(connections['connected_peers']), 0) self.assertEqual(len(connections['handshaking_peers']), 1) self.assertEqual(connections['handshaking_peers'][0]['address'], handshake_address) @inlineCallbacks def test_get_with_one_peer(self): self.conn1.run_one_step() # HELLO self.conn1.run_one_step() # PEER-ID self.conn1.run_one_step() # READY self.conn1.run_one_step() # BOTH PEERS ARE READY NOW response = yield self.web.get("status") data = response.json_value() server_data = data.get('server') known_peers = data.get('known_peers') connections = data.get('connections') self.assertEqual(server_data['app_version'], 'Hathor v{}'.format(hathor.__version__)) self.assertEqual(server_data['network'], 'testnet') self.assertGreater(server_data['uptime'], 0) self.assertEqual(len(known_peers), 1) self.assertEqual(known_peers[0]['id'], self.manager2.my_peer.id) self.assertEqual(len(connections['connected_peers']), 1) self.assertEqual(connections['connected_peers'][0]['id'], self.manager2.my_peer.id) @inlineCallbacks def test_connecting_peers(self): address = '192.168.1.1:54321' endpoint = endpoints.clientFromString(self.manager.reactor, 'tcp:{}'.format(address)) deferred = endpoint.connect self.manager.connections.connecting_peers[endpoint] = deferred response = yield self.web.get("status") data = response.json_value() connecting = data['connections']['connecting_peers'] self.assertEqual(len(connecting), 1) self.assertEqual(connecting[0]['address'], address) self.assertIsNotNone(connecting[0]['deferred'])
def setUp(self): super().setUp() self.web = StubSite(PushTxResource(self.manager)) self.web_tokens = StubSite(SendTokensResource(self.manager))
def setUp(self): super().setUp() self.web = StubSite(TxParentsResource(self.manager))
class UnlockTest(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() self.web = StubSite(UnlockWalletResource(self.manager)) self.web_lock = StubSite(LockWalletResource(self.manager)) self.web_state = StubSite(StateWalletResource(self.manager)) @inlineCallbacks def test_unlocking(self): # Wallet is locked response = yield self.web_state.get("wallet/state") data = response.json_value() self.assertTrue(data['is_locked']) # Try to unlock with wrong password # Options yield self.web.options("wallet/unlock") response_error = yield self.web.post("wallet/unlock", {'password': '******'}) data_error = response_error.json_value() self.assertFalse(data_error['success']) # Try to unlock with correct password response_success = yield self.web.post("wallet/unlock", {'password': '******'}) data_success = response_success.json_value() self.assertTrue(data_success['success']) # Wallet is unlocked response_unlocked = yield self.web_state.get("wallet/state") data_unlocked = response_unlocked.json_value() self.assertFalse(data_unlocked['is_locked']) @inlineCallbacks def test_unlocking_hd_wallet(self): self.manager.wallet = HDWallet() self.manager.wallet._manually_initialize() self.manager.wallet.unlock(tx_storage=self.manager.tx_storage) # Wallet is not locked response = yield self.web_state.get("wallet/state") data = response.json_value() self.assertFalse(data['is_locked']) # Lock the wallet response_lock = yield self.web_lock.post("wallet/lock") data_lock = response_lock.json_value() self.assertTrue(data_lock['success']) # Wallet is locked response_locked = yield self.web_state.get("wallet/state") data_locked = response_locked.json_value() self.assertTrue(data_locked['is_locked']) # Unlock wallet invalid words response_invalid = yield self.web.post("wallet/unlock", { 'words': 'abc def', 'passphrase': '' }) data_invalid = response_invalid.json_value() self.assertFalse(data_invalid['success']) # Unlock wallet response_success = yield self.web.post("wallet/unlock", {'passphrase': ''}) data_success = response_success.json_value() self.assertTrue(data_success['success']) # Wallet is unlocked response_unlocked = yield self.web_state.get("wallet/state") data_unlocked = response_unlocked.json_value() self.assertFalse(data_unlocked['is_locked']) # Lock the wallet and unlock with same words self.manager.wallet.lock() response_words = yield self.web.post("wallet/unlock", { 'words': data_success['words'], 'passphrase': '' }) data_words = response_words.json_value() self.assertTrue(data_words['success'])
def setUp(self): super().setUp() self.web = StubSite(ProfilerResource(self.manager))
class TestWebsocket(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() self.network = 'testnet' self.manager = self.create_peer(self.network, wallet_index=True) self.factory = HathorAdminWebsocketFactory(self.manager.metrics) self.factory.subscribe(self.manager.pubsub) self.factory._setup_rate_limit() self.factory.openHandshakeTimeout = 0 self.protocol = self.factory.buildProtocol(None) self.transport = proto_helpers.StringTransport() self.protocol.makeConnection(self.transport) self.web = StubSite(WebsocketStatsResource(self.factory)) def _decode_value(self, value): ret = None while value: try: ret = json.loads(value.decode('utf-8')) break except (UnicodeDecodeError, json.decoder.JSONDecodeError): value = value[1:] return ret def test_new_tx(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN self.manager.pubsub.publish(HathorEvents.NETWORK_NEW_TX_ACCEPTED, tx=get_genesis_transactions( self.manager.tx_storage)[1]) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['tx_id'], get_genesis_transactions(None)[1].hash.hex()) self.assertEqual(value['type'], 'network:new_tx_accepted') def test_metric(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN self.factory._schedule_and_send_metric() value = self._decode_value(self.transport.value()) keys = [ 'transactions', 'blocks', 'best_block_height', 'hash_rate', 'block_hash_rate', 'tx_hash_rate', 'network_hash_rate', 'peers', 'type', 'time' ] self.assertEqual(len(value), len(keys)) for key in keys: self.assertTrue(key in value) def test_balance(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN self.manager.pubsub.publish( HathorEvents.WALLET_BALANCE_UPDATED, balance={settings.HATHOR_TOKEN_UID: WalletBalance(10, 20)}) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['balance']['locked'], 10) self.assertEqual(value['balance']['available'], 20) self.assertEqual(value['type'], 'wallet:balance_updated') def test_gap_limit(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN self.manager.pubsub.publish(HathorEvents.WALLET_GAP_LIMIT, limit=10) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['limit'], 10) self.assertEqual(value['type'], 'wallet:gap_limit') def test_output_received(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN gen_tx = get_genesis_transactions(None)[0] output = UnspentTx(gen_tx.hash, 0, 10, gen_tx.timestamp, '', gen_tx.outputs[0].token_data) self.manager.pubsub.publish(HathorEvents.WALLET_OUTPUT_RECEIVED, total=10, output=output) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['total'], 10) self.assertEqual(value['type'], 'wallet:output_received') self.assertEqual(value['output']['tx_id'], gen_tx.hash.hex()) def test_input_spent_received(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN gen_tx = get_genesis_transactions(None)[0] gen_tx2 = get_genesis_transactions(None)[1] spent = SpentTx(gen_tx2.hash, gen_tx.hash, 0, 10, gen_tx.timestamp + 1) self.manager.pubsub.publish(HathorEvents.WALLET_INPUT_SPENT, output_spent=spent) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['type'], 'wallet:output_spent') self.assertEqual(value['output_spent']['tx_id'], gen_tx2.hash.hex()) self.assertEqual(value['output_spent']['from_tx_id'], gen_tx.hash.hex()) def test_invalid_publish(self): self.factory.connections.add(self.protocol) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN self.manager.pubsub.publish(HathorEvents.NETWORK_PEER_CONNECTED) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertIsNone(value) with self.assertRaises(ValueError): kwargs = {} args = EventArguments(**kwargs) self.factory.serialize_message_data( HathorEvents.NETWORK_PEER_CONNECTED, args) def test_ping(self): self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN payload = json.dumps({'type': 'ping'}).encode('utf-8') self.protocol.onMessage(payload, True) value = self._decode_value(self.transport.value()) self.assertEqual(value['type'], 'pong') def test_ping_str(self): self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN payload = json.dumps({'type': 'ping'}) self.protocol.onMessage(payload, False) value = self._decode_value(self.transport.value()) self.assertEqual(value['type'], 'pong') def test_subscribe_address(self): self.assertEqual(len(self.factory.address_connections), 0) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN # Subscribe to address address = '1Q4qyTjhpUXUZXzwKs6Yvh2RNnF5J1XN9a' payload = json.dumps({ 'type': 'subscribe_address', 'address': address }).encode('utf-8') self.protocol.onMessage(payload, True) self.assertEqual(len(self.factory.address_connections), 1) block_genesis = [ tx for tx in get_genesis_transactions(self.manager.tx_storage) if tx.is_block ][0] # Test publish address history # First clean the transport to make sure the value comes from this execution self.transport.clear() element = block_genesis.to_json_extended() self.manager.pubsub.publish(HathorEvents.WALLET_ADDRESS_HISTORY, address=address, history=element) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertEqual(value['type'], 'wallet:address_history') self.assertEqual(value['address'], address) self.assertEqual(value['history']['tx_id'], block_genesis.hash_hex) self.assertEqual(value['history']['timestamp'], block_genesis.timestamp) # Publishing with address that was not subscribed must not generate any value in the ws # First clean the transport to make sure the value comes from this execution self.transport.clear() wrong_address = '1Q4qyTjhpUXUZXzwKs6Yvh2RNnF5J1XN9b' self.manager.pubsub.publish(HathorEvents.WALLET_ADDRESS_HISTORY, address=wrong_address, history=element) self.run_to_completion() value = self._decode_value(self.transport.value()) self.assertIsNone(value) def test_connections(self): self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN request_mock = Mock(peer=None) self.protocol.onConnect(request_mock) self.assertEqual(len(self.factory.connections), 0) self.protocol.onOpen() self.assertEqual(len(self.factory.connections), 1) self.protocol.onClose(True, 1, 'Closed') self.assertEqual(len(self.factory.connections), 0) def test_invalid_metric_key(self): kwargs = {'test': False} arg = EventArguments(**kwargs) with self.assertRaises(ValueError): self.manager.metrics.handle_publish('invalid_key', arg) metrics = Metrics( pubsub=self.manager.pubsub, avg_time_between_blocks=self.manager.avg_time_between_blocks, tx_storage=self.manager.tx_storage, ) self.assertNotEqual(metrics.reactor, self.manager.reactor) hash_rate = metrics.get_current_hash_rate( metrics.weight_block_deque, metrics.total_block_weight, metrics.set_current_block_hash_rate, metrics.block_hash_store_interval) self.assertEqual(hash_rate, 0) @inlineCallbacks def test_get_stats(self): response = yield self.web.get('websocket_stats') data = response.json_value() self.assertEqual(data['connections'], 0) self.assertEqual(data['subscribed_addresses'], 0) # Add one connection self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN request_mock = Mock(peer=None) self.protocol.onConnect(request_mock) self.protocol.onOpen() # Add two addresses self.assertEqual(len(self.factory.address_connections), 0) self.protocol.state = HathorAdminWebsocketProtocol.STATE_OPEN # Subscribe to address address1 = '1Q4qyTjhpUXUZXzwKs6Yvh2RNnF5J1XN9a' payload = json.dumps({ 'type': 'subscribe_address', 'address': address1 }).encode('utf-8') self.protocol.onMessage(payload, True) address2 = '1Q4qyTjhpUXUZXzwKs6Yvh2RNnF5J1XN9b' payload = json.dumps({ 'type': 'subscribe_address', 'address': address2 }).encode('utf-8') self.protocol.onMessage(payload, True) # Test get again response = yield self.web.get('websocket_stats') data = response.json_value() self.assertEqual(data['connections'], 1) self.assertEqual(data['subscribed_addresses'], 2)
def test_token_history(self): self.manager.wallet.unlock(b'MYPASS') resource = StubSite(TokenHistoryResource(self.manager)) add_new_blocks(self.manager, 1, advance_clock=1) add_blocks_unlock_reward(self.manager) tx = create_tokens(self.manager, mint_amount=100, token_name='Teste', token_symbol='TST') token_uid = tx.tokens[0] response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'3' }) data = response.json_value() # Success returning the token creation tx self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get('thin_wallet/token_history', { b'id': b'123', b'count': b'3' }) data = response.json_value() # Fail because token is unknown self.assertFalse(data['success']) # Create a tx with this token, so we can have more tx in the history output = tx.outputs[0] script_type_out = parse_address_script(output.script) address = script_type_out.address private_key = self.manager.wallet.get_private_key(address) output_address = decode_address(self.get_address(0)) o = TxOutput(100, create_output_script(output_address, None), 1) i = TxInput(tx.hash, 0, b'') tx2 = Transaction(inputs=[i], outputs=[o], tokens=[token_uid]) data_to_sign = tx2.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) i.data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx2.inputs = [i] tx2.timestamp = int(self.clock.seconds()) tx2.weight = self.manager.minimum_tx_weight(tx2) tx2.parents = self.manager.get_new_tx_parents() tx2.resolve() self.manager.propagate_tx(tx2) # Now we have 2 txs with this token response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'3' }) data = response.json_value() # Success returning the token creation tx and newly created tx self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(2, len(data['transactions'])) self.assertEqual(tx2.hash.hex(), data['transactions'][0]['tx_id']) self.assertEqual(tx.hash.hex(), data['transactions'][1]['tx_id']) response = yield resource.get('thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'1' }) data = response.json_value() # Testing has_more self.assertTrue(data['success']) self.assertTrue(data['has_more']) self.assertEqual(1, len(data['transactions'])) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'10', b'page': b'next', b'hash': tx2.hash.hex().encode(), b'timestamp': str(tx2.timestamp).encode(), }) data = response.json_value() # Testing next self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'10', b'page': b'previous', b'hash': tx.hash.hex().encode(), b'timestamp': str(tx.timestamp).encode(), }) data = response.json_value() # Testing previous self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(1, len(data['transactions'])) self.assertEqual(tx2.hash.hex(), data['transactions'][0]['tx_id']) response = yield resource.get( 'thin_wallet/token_history', { b'id': token_uid.hex().encode(), b'count': b'10', b'page': b'previous', b'hash': tx2.hash.hex().encode(), b'timestamp': str(tx2.timestamp).encode(), }) data = response.json_value() # Testing previous from first self.assertTrue(data['success']) self.assertFalse(data['has_more']) self.assertEqual(0, len(data['transactions']))
def setUp(self): super().setUp() self.web = StubSite(TipsHistogramResource(self.manager)) self.manager.wallet.unlock(b'MYPASS') self.manager.reactor.advance(time.time())
def test_token_history_invalid_params(self): resource = StubSite(TokenHistoryResource(self.manager)) # invalid count response = yield resource.get( 'thin_wallet/token_history', { b'id': b'000003a3b261e142d3dfd84970d3a50a93b5bc3a66a3b6ba973956148a3eb824', b'count': b'a' }) data = response.json_value() self.assertFalse(data['success']) # missing token uid response = yield resource.get('thin_wallet/token_history', {b'count': b'3'}) data = response.json_value() self.assertFalse(data['success']) # invalid token uid response = yield resource.get('thin_wallet/token_history', { b'id': b'000', b'count': b'3' }) data = response.json_value() self.assertFalse(data['success']) # missing timestamp response = yield resource.get( 'thin_wallet/token_history', { b'id': b'000003a3b261e142d3dfd84970d3a50a93b5bc3a66a3b6ba973956148a3eb824', b'count': b'3', b'hash': b'0000b1448893eb7efdd3c71b97b74d934a4ecaaf8a6b52f6cb5b60fdaf21497b', }) data = response.json_value() self.assertFalse(data['success']) # invalid timestamp response = yield resource.get( 'thin_wallet/token_history', { b'id': b'000003a3b261e142d3dfd84970d3a50a93b5bc3a66a3b6ba973956148a3eb824', b'count': b'3', b'hash': b'0000b1448893eb7efdd3c71b97b74d934a4ecaaf8a6b52f6cb5b60fdaf21497b', b'timestamp': b'a' }) data = response.json_value() self.assertFalse(data['success']) # invalid hash response = yield resource.get( 'thin_wallet/token_history', { b'id': b'000003a3b261e142d3dfd84970d3a50a93b5bc3a66a3b6ba973956148a3eb824', b'count': b'3', b'timestamp': b'1578118186', b'page': b'next', b'hash': b'000', }) data = response.json_value() self.assertFalse(data['success']) # invalid page response = yield resource.get( 'thin_wallet/token_history', { b'id': b'000003a3b261e142d3dfd84970d3a50a93b5bc3a66a3b6ba973956148a3eb824', b'count': b'3', b'timestamp': b'1578118186', b'page': b'nextYY', b'hash': b'0000b1448893eb7efdd3c71b97b74d934a4ecaaf8a6b52f6cb5b60fdaf21497b', }) data = response.json_value() self.assertFalse(data['success'])
def setUp(self): super().setUp() self.web = StubSite(DecodeTxResource(self.manager))
def setUp(self): super().setUp() self.web = StubSite(ValidateAddressResource(self.manager))
class MiningTest(_BaseResourceTest._ResourceTest): def setUp(self): super().setUp() self.web = StubSite(MiningResource(self.manager)) @inlineCallbacks def test_get(self): response = yield self.web.get('mining') data = response.json_value() self.assertGreater(len(data['parents']), 0) self.assertIsNotNone(data.get('block_bytes')) @inlineCallbacks def test_post(self): response_get = yield self.web.get('mining') data_get = response_get.json_value() block_bytes_str = data_get.get('block_bytes') block_bytes = base64.b64decode(block_bytes_str) block = Block.create_from_struct(block_bytes) block.weight = 4 block.resolve() block_bytes = bytes(block) block_bytes_str = base64.b64encode(block_bytes).decode('ascii') response_post = yield self.web.post('mining', {'block_bytes': block_bytes_str}) self.assertEqual(response_post.written[0], b'1') block.weight = 100 block_bytes = bytes(block) block_bytes_str = base64.b64encode(block_bytes).decode('ascii') response_post = yield self.web.post('mining', {'block_bytes': block_bytes_str}) # Probability 2^(100 - 256) of failing self.assertEqual(response_post.written[0], b'0') @inlineCallbacks def test_post_invalid_data(self): response_get = yield self.web.get('mining') data_get = response_get.json_value() block_bytes_str = data_get.get('block_bytes') block_bytes = base64.b64decode(block_bytes_str) block = Block.create_from_struct(block_bytes) block.weight = 4 block.resolve() block_bytes = bytes(block) block_bytes_str = base64.b64encode(block_bytes).decode('ascii') # missing post data response_post = yield self.web.post('mining') self.assertEqual(response_post.written[0], b'0') # invalid block bytes response_post = yield self.web.post('mining', {'block_bytes': base64.b64encode(b'aaa').decode('ascii')}) self.assertEqual(response_post.written[0], b'0') # invalid base64 response_post = yield self.web.post('mining', {'block_bytes': 'YWFha'}) self.assertEqual(response_post.written[0], b'0')
def setUp(self): super().setUp() self.web = StubSite(TransactionAccWeightResource(self.manager)) self.manager.wallet.unlock(b'MYPASS')
def setUp(self): super().setUp() self.web = StubSite(SendTokensResource(self.manager)) self.web_mining = StubSite(MiningResource(self.manager)) self.web_balance = StubSite(BalanceResource(self.manager)) self.web_history = StubSite(HistoryResource(self.manager))
class BasePushTxTest(_BaseResourceTest._ResourceTest): __test__ = False is_post: Optional[bool] = None # XXX: we will get a "two instances of the same tx in memory" otherwise use_memory_storage = True def setUp(self): super().setUp() self.web = StubSite(PushTxResource(self.manager)) self.web_tokens = StubSite(SendTokensResource(self.manager)) def get_tx( self, inputs: Optional[List[WalletInputInfo]] = None, outputs: Optional[List[WalletOutputInfo]] = None) -> Transaction: if not outputs: address = self.get_address(0) assert address is not None outputs = [ WalletOutputInfo(address=decode_address(address), value=1, timelock=None), WalletOutputInfo(address=decode_address(address), value=1, timelock=None) ] if inputs: tx = self.manager.wallet.prepare_transaction( Transaction, inputs, outputs) else: tx = self.manager.wallet.prepare_transaction_compute_inputs( Transaction, outputs, self.manager.tx_storage) tx.storage = self.manager.tx_storage tx.weight = 1 max_ts_spent_tx = max( tx.get_spent_tx(txin).timestamp for txin in tx.inputs) tx.timestamp = max(max_ts_spent_tx + 1, int(self.manager.reactor.seconds())) tx.parents = self.manager.get_new_tx_parents(tx.timestamp) tx.resolve() return tx def push_tx(self, data=None): if self.is_post is None: raise Exception( 'You must set self.is_push before calling this method.') if self.is_post: body = data return self.web.post('push_tx', body) if data is None: args = None else: args = {} for k, v in data.items(): nk = k.encode() if isinstance(v, str): nv = v.encode() elif isinstance(v, bool): nv = b'true' if v else b'false' else: raise NotImplementedError args[nk] = nv return self.web.get('push_tx', args) @inlineCallbacks def test_push_tx(self) -> Generator: self.manager.wallet.unlock(b'MYPASS') blocks = add_new_blocks(self.manager, 5, advance_clock=15) add_blocks_unlock_reward(self.manager) tx = self.get_tx() tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex}) data = response.json_value() self.assertTrue(data['success']) # Sending token to random address without input data_json = { 'outputs': [{ 'address': self.get_address(0), 'value': 5 }], 'inputs': [] } yield self.web_tokens.post('wallet/send_tokens', {'data': data_json}) # modify tx so it will be a double spending, then rejected tx.weight += 0.1 tx.resolve() tx_hex = tx.get_struct().hex() response_success = yield self.push_tx({'hex_tx': tx_hex}) data_success = response_success.json_value() self.assertFalse(data_success['success']) # invalid transaction, without forcing tx.timestamp = 5 tx.inputs = [TxInput(blocks[1].hash, 0, b'')] script_type_out = parse_address_script(blocks[1].outputs[0].script) assert script_type_out is not None private_key = self.manager.wallet.get_private_key( script_type_out.address) data_to_sign = tx.get_sighash_all() public_key_bytes, signature_bytes = self.manager.wallet.get_input_aux_data( data_to_sign, private_key) tx.inputs[0].data = P2PKH.create_input_data(public_key_bytes, signature_bytes) tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex}) data = response.json_value() self.assertFalse(data['success']) # force tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex, 'force': True}) data = response.json_value() self.assertFalse(data['success']) # Invalid tx (don't have inputs) genesis_tx = next(x for x in self.manager.tx_storage.get_all_genesis() if x.is_transaction) genesis_hex = genesis_tx.get_struct().hex() response_genesis = yield self.push_tx({'tx_hex': genesis_hex}) data_genesis = response_genesis.json_value() self.assertFalse(data_genesis['success']) # Token creation tx script_type_out = parse_address_script(blocks[0].outputs[0].script) assert script_type_out is not None address = script_type_out.address tx2 = create_tokens(self.manager, address, mint_amount=100, propagate=False) tx2_hex = tx2.get_struct().hex() response = yield self.push_tx({'hex_tx': tx2_hex}) data = response.json_value() self.assertTrue(data['success']) @inlineCallbacks def test_push_nft(self) -> Generator: self.manager.wallet.unlock(b'MYPASS') blocks = add_new_blocks(self.manager, 5, advance_clock=15) add_blocks_unlock_reward(self.manager) # NFT creation tx script_type_out = parse_address_script(blocks[0].outputs[0].script) assert script_type_out is not None address = script_type_out.address tx3 = create_tokens(self.manager, address, mint_amount=100, propagate=False, nft_data='test') tx3_hex = tx3.get_struct().hex() response = yield self.push_tx({'hex_tx': tx3_hex}) data = response.json_value() self.assertTrue(data['success']) @inlineCallbacks def test_invalid_params(self) -> Generator: # Missing hex response = yield self.push_tx() data = response.json_value() self.assertFalse(data['success']) # Missing hex 2 response = yield self.push_tx({}) data = response.json_value() self.assertFalse(data['success']) # Invalid hex response = yield self.push_tx({'hex_tx': 'XXXX'}) data = response.json_value() self.assertFalse(data['success']) # Invalid tx hex response_error2 = yield self.push_tx({'hex_tx': 'a12c'}) data_error2 = response_error2.json_value() self.assertFalse(data_error2['success']) @inlineCallbacks def test_script_too_big(self) -> Generator: self.manager.wallet.unlock(b'MYPASS') add_new_blocks(self.manager, 5, advance_clock=15) add_blocks_unlock_reward(self.manager) tx = self.get_tx() # Invalid tx (output script is too long) tx.outputs[0].script = b'*' * (settings.PUSHTX_MAX_OUTPUT_SCRIPT_SIZE + 1) tx.resolve() tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex}) data = response.json_value() self.assertFalse(data['success']) self.assertEqual('Transaction is non standard.', data['message']) @inlineCallbacks def test_non_standard_script(self) -> Generator: self.manager.wallet.unlock(b'MYPASS') add_new_blocks(self.manager, 5, advance_clock=15) add_blocks_unlock_reward(self.manager) tx = self.get_tx() # Invalid tx (output script is too long) tx.outputs[0].script = b'*' * 5 tx.resolve() tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex}) data = response.json_value() self.assertFalse(data['success']) expected = 'Transaction is non standard.' self.assertEqual(expected, data['message']) @inlineCallbacks def test_spending_voided(self) -> Generator: self.manager.wallet.unlock(b'MYPASS') add_new_blocks(self.manager, 5, advance_clock=15) add_blocks_unlock_reward(self.manager) # Push a first tx tx = self.get_tx() tx_hex = tx.get_struct().hex() response = yield self.push_tx({'hex_tx': tx_hex}) data = response.json_value() self.assertTrue(data['success']) wallet = self.manager.wallet # Pushing a tx that spends this first tx works txout = tx.outputs[0] p2pkh = parse_address_script(txout.script) assert p2pkh is not None private_key = wallet.get_private_key(p2pkh.address) assert tx.hash is not None inputs = [ WalletInputInfo(tx_id=tx.hash, index=0, private_key=private_key) ] outputs = [ WalletOutputInfo(address=decode_address(p2pkh.address), value=txout.value, timelock=None), ] tx2 = self.get_tx(inputs, outputs) tx2_hex = tx2.get_struct().hex() response = yield self.push_tx({'hex_tx': tx2_hex}) data = response.json_value() self.assertTrue(data['success']) # Now we set this tx2 as voided and try to push a tx3 that spends tx2 tx_meta = tx2.get_metadata() assert tx2.hash is not None tx_meta.voided_by = {tx2.hash} self.manager.tx_storage.save_transaction(tx2, only_metadata=True) inputs = [ WalletInputInfo(tx_id=tx2.hash, index=0, private_key=private_key) ] outputs = [ WalletOutputInfo(address=decode_address(p2pkh.address), value=txout.value, timelock=None), ] tx3 = self.get_tx(inputs, outputs) tx3_hex = tx3.get_struct().hex() response = yield self.push_tx({'hex_tx': tx3_hex}) data = response.json_value() self.assertFalse(data['success']) # Now we set this tx2 as voided and try to push a tx3 that spends tx2 tx_meta = tx2.get_metadata() tx_meta.voided_by = {settings.SOFT_VOIDED_ID} self.manager.tx_storage.save_transaction(tx2, only_metadata=True) # Try to push again with soft voided id as voided by response = yield self.push_tx({'hex_tx': tx3_hex}) data = response.json_value() self.assertFalse(data['success']) # Now without voided_by the push tx must succeed tx_meta = tx2.get_metadata() tx_meta.voided_by = None self.manager.tx_storage.save_transaction(tx2, only_metadata=True) response = yield self.push_tx({'hex_tx': tx3_hex}) data = response.json_value() self.assertTrue(data['success'])
def test_token(self): self.manager.wallet.unlock(b'MYPASS') resource = StubSite(TokenResource(self.manager)) # test list of tokens empty response_list1 = yield resource.get('thin_wallet/token') data_list1 = response_list1.json_value() self.assertTrue(data_list1['success']) self.assertEqual(len(data_list1['tokens']), 0) # test invalid token id response = yield resource.get('thin_wallet/token', {b'id': 'vvvv'.encode()}) data = response.json_value() self.assertFalse(data['success']) # test unknown token id unknown_uid = '00000000228ed1dd74a2e1b920c1d64bf81dc63875dce4fac486001073b45a27'.encode( ) response = yield resource.get('thin_wallet/token', {b'id': unknown_uid}) data = response.json_value() self.assertFalse(data['success']) # test success case add_new_blocks(self.manager, 1, advance_clock=1) add_blocks_unlock_reward(self.manager) token_name = 'MyTestToken' token_symbol = 'MTT' amount = 150 tx = create_tokens(self.manager, mint_amount=amount, token_name=token_name, token_symbol=token_symbol, use_genesis=False) token_uid = tx.tokens[0] response = yield resource.get('thin_wallet/token', {b'id': token_uid.hex().encode()}) data = response.json_value() self.assertTrue(data['success']) self.assertEqual(len(data['mint']), 1) self.assertEqual(len(data['melt']), 1) self.assertEqual(data['mint'][0]['tx_id'], tx.hash_hex) self.assertEqual(data['melt'][0]['tx_id'], tx.hash_hex) self.assertEqual(data['mint'][0]['index'], 1) self.assertEqual(data['melt'][0]['index'], 2) self.assertEqual(data['total'], amount) self.assertEqual(data['name'], token_name) self.assertEqual(data['symbol'], token_symbol) # test list of tokens with one token response_list2 = yield resource.get('thin_wallet/token') data_list2 = response_list2.json_value() self.assertTrue(data_list2['success']) self.assertEqual(len(data_list2['tokens']), 1) self.assertEqual(data_list2['tokens'][0]['name'], token_name) self.assertEqual(data_list2['tokens'][0]['symbol'], token_symbol) self.assertEqual(data_list2['tokens'][0]['uid'], tx.hash.hex()) token_name2 = 'New Token' token_symbol2 = 'NTK' tx2 = create_tokens(self.manager, mint_amount=amount, token_name=token_name2, token_symbol=token_symbol2, use_genesis=False) token_name3 = 'Wat Coin' token_symbol3 = 'WTC' tx3 = create_tokens(self.manager, mint_amount=amount, token_name=token_name3, token_symbol=token_symbol3, use_genesis=False) # test list of tokens with 3 tokens response_list3 = yield resource.get('thin_wallet/token') data_list3 = response_list3.json_value() self.assertTrue(data_list3['success']) self.assertEqual(len(data_list3['tokens']), 3) token1 = { 'uid': tx.hash.hex(), 'name': token_name, 'symbol': token_symbol } token2 = { 'uid': tx2.hash.hex(), 'name': token_name2, 'symbol': token_symbol2 } token3 = { 'uid': tx3.hash.hex(), 'name': token_name3, 'symbol': token_symbol3 } self.assertIn(token1, data_list3['tokens']) self.assertIn(token2, data_list3['tokens']) self.assertIn(token3, data_list3['tokens']) # test no wallet index manager2 = self.create_peer(self.network, unlock_wallet=True) resource2 = StubSite(TokenResource(manager2)) response2 = yield resource2.get('thin_wallet/token') data2 = response2.json_value() self.assertEqual(response2.responseCode, 503) self.assertFalse(data2['success'])
def setUp(self): super().setUp() self.web = StubSite(MempoolResource(self.manager)) self.manager.wallet.unlock(b'MYPASS') add_new_blocks(self.manager, 4, advance_clock=1) add_blocks_unlock_reward(self.manager)