def test_find_p2pkh(self): with self.assertRaises(MissingStackItems): op_find_p2pkh([], log=[], extras=None) addr1 = '15d14K5jMqsN2uwUEFqiPG5SoD7Vr1BfnH' addr2 = '1K35zJQeYrVzQAW7X3s7vbPKmngj5JXTBc' addr3 = '1MnHN3D41yaMN5WLLKPARRdF77USvPLDfy' import base58 out1 = P2PKH.create_output_script(base58.b58decode(addr1)) out2 = P2PKH.create_output_script(base58.b58decode(addr2)) out3 = P2PKH.create_output_script(base58.b58decode(addr3)) # read genesis keys genesis_address = get_address_from_public_key(self.genesis_public_key) out_genesis = P2PKH.create_output_script(genesis_address) from hathor.transaction import Transaction, TxOutput, TxInput spent_tx = Transaction(outputs=[TxOutput(1, b'nano_contract_code')]) txin = TxInput(b'dont_care', 0, b'data') # try with just 1 output stack = [genesis_address] tx = Transaction(outputs=[TxOutput(1, out_genesis)]) extras = ScriptExtras(tx=tx, txin=txin, spent_tx=spent_tx) op_find_p2pkh(stack, log=[], extras=extras) self.assertEqual(stack.pop(), 1) # several outputs and correct output among them stack = [genesis_address] tx = Transaction(outputs=[TxOutput(1, out1), TxOutput(1, out2), TxOutput(1, out_genesis), TxOutput(1, out3)]) extras = ScriptExtras(tx=tx, txin=txin, spent_tx=spent_tx) op_find_p2pkh(stack, log=[], extras=extras) self.assertEqual(stack.pop(), 1) # several outputs without correct amount output stack = [genesis_address] tx = Transaction(outputs=[TxOutput(1, out1), TxOutput(1, out2), TxOutput(2, out_genesis), TxOutput(1, out3)]) extras = ScriptExtras(tx=tx, txin=txin, spent_tx=spent_tx) with self.assertRaises(VerifyFailed): op_find_p2pkh(stack, log=[], extras=extras) # several outputs without correct address output stack = [genesis_address] tx = Transaction(outputs=[TxOutput(1, out1), TxOutput(1, out2), TxOutput(1, out3)]) extras = ScriptExtras(tx=tx, txin=txin, spent_tx=spent_tx) with self.assertRaises(VerifyFailed): op_find_p2pkh(stack, log=[], extras=extras)
def test_token_transfer(self): wallet = self.manager.wallet tx = create_tokens(self.manager, self.address_b58) token_uid = tx.tokens[0] utxo = tx.outputs[0] parents = self.manager.get_new_tx_parents() _input1 = TxInput(tx.hash, 0, b'') script = P2PKH.create_output_script(self.address) # regular transfer token_output = TxOutput(utxo.value, script, 1) tx2 = Transaction(weight=1, inputs=[_input1], outputs=[token_output], parents=parents, tokens=[token_uid], storage=self.manager.tx_storage, timestamp=int(self.clock.seconds())) data_to_sign = tx2.get_sighash_all(clear_input_data=True) public_bytes, signature = wallet.get_input_aux_data(data_to_sign, wallet.get_private_key(self.address_b58)) tx2.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx2.resolve() tx2.verify() # missing tokens token_output = TxOutput(utxo.value - 1, script, 1) tx3 = Transaction(weight=1, inputs=[_input1], outputs=[token_output], parents=parents, tokens=[token_uid], storage=self.manager.tx_storage, timestamp=int(self.clock.seconds())) data_to_sign = tx3.get_sighash_all(clear_input_data=True) public_bytes, signature = wallet.get_input_aux_data(data_to_sign, wallet.get_private_key(self.address_b58)) tx3.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx3.resolve() with self.assertRaises(InputOutputMismatch): tx3.verify()
def test_regular_tx(self): # this should succeed parents = [tx.hash for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) _input = TxInput(genesis_block.hash, 0, b'') tx = Transaction(weight=1, inputs=[_input], outputs=[output], parents=parents, storage=self.tx_storage, timestamp=self.last_block.timestamp + 1) data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) _input.data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() tx.verify()
def test_update_timestamp(self): parents = [tx for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) # update based on input _input = TxInput(genesis_block.hash, 0, b'') tx = Transaction(weight=1, inputs=[_input], outputs=[output], parents=[p.hash for p in parents], storage=self.tx_storage) input_timestamp = genesis_block.timestamp max_ts = max(input_timestamp, parents[0].timestamp, parents[1].timestamp) tx.update_timestamp(0) self.assertEquals(tx.timestamp, max_ts + 1) ts = max_ts + 20 tx.update_timestamp(ts) self.assertEquals(tx.timestamp, ts)
def test_tx_duplicated_parents(self): # the new tx will confirm the same tx twice parents = [self.genesis_txs[0].hash, self.genesis_txs[0].hash] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) _input = TxInput(genesis_block.hash, 0, b'') tx = Transaction(weight=1, inputs=[_input], outputs=[output], parents=parents, storage=self.tx_storage, timestamp=self.last_block.timestamp + 1) data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) _input.data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() with self.assertRaises(DuplicatedParents): tx.verify()
def test_match_values(self): pubkey_hash = '6o6ul2c+sqAariBVW+CwNaSJb9w=' pubkey = 'Awmloohhey8WhajdDURgvbk1z3JHX2vxDSBjz9uG9wEp' # ./hathor-cli oracle-encode-data str:some_id int:1543974403 int:100 oracle_data = 'B3NvbWVfaWQEXAcuAwFk' oracle_signature = 'MEYCIQC5cyg1tOY4oyPZ5KY7ugWJGRShrsSPxr8AxxyuvO5PYwIhAOxHBDMid7aRXe' \ '+85rIaDPI2ussIcw54avaFWfT9svSp' address = base58.b58decode(self.get_address(0)) # they should be the same nc = NanoContractMatchValues(base64.b64decode(pubkey_hash), 1543970403, 'some_id'.encode('utf-8'), {address: 100}) script = nc.create_output_script() nc2 = NanoContractMatchValues.parse_script(script) self.assertIsNotNone(nc2) self.assertEqual(json.dumps(nc.to_human_readable()), json.dumps(nc2.to_human_readable())) # if we add some more bytes, parsing should not match script2 = script + b'00' nc3 = NanoContractMatchValues.parse_script(script2) self.assertIsNone(nc3) # test script eval is true input_data = NanoContractMatchValues.create_input_data( base64.b64decode(oracle_data), base64.b64decode(oracle_signature), base64.b64decode(pubkey)) txin = TxInput(b'aa', 0, input_data) spent_tx = Transaction(outputs=[TxOutput(20, script)]) tx = Transaction( outputs=[TxOutput(20, P2PKH.create_output_script(address))]) script_eval(tx, txin, spent_tx)
def test_token_transfer_authority(self): wallet = self.manager.wallet tx = create_tokens(self.manager, self.address_b58) token_uid = tx.tokens[0] parents = self.manager.get_new_tx_parents() script = P2PKH.create_output_script(self.address) # input with mint and output with melt _input1 = TxInput(tx.hash, 1, b'') token_output = TxOutput(TxOutput.TOKEN_MELT_MASK, script, 0b10000001) tx2 = Transaction(weight=1, inputs=[_input1], outputs=[token_output], parents=parents, tokens=[token_uid], storage=self.manager.tx_storage, timestamp=int(self.clock.seconds())) data_to_sign = tx2.get_sighash_all(clear_input_data=True) public_bytes, signature = wallet.get_input_aux_data(data_to_sign, wallet.get_private_key(self.address_b58)) tx2.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx2.resolve() with self.assertRaises(InvalidToken): tx2.verify() # input with melt and output with mint _input1 = TxInput(tx.hash, 2, b'') token_output = TxOutput(TxOutput.TOKEN_MINT_MASK, script, 0b10000001) tx3 = Transaction(weight=1, inputs=[_input1], outputs=[token_output], parents=parents, tokens=[token_uid], storage=self.manager.tx_storage, timestamp=int(self.clock.seconds())) data_to_sign = tx3.get_sighash_all(clear_input_data=True) public_bytes, signature = wallet.get_input_aux_data(data_to_sign, wallet.get_private_key(self.address_b58)) tx3.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx3.resolve() with self.assertRaises(InvalidToken): tx3.verify()
def test_weight_inf(self): # this should succeed parents = [tx.hash for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) _input = TxInput(genesis_block.hash, 0, b'') tx = Transaction(inputs=[_input], outputs=[output], parents=parents, storage=self.tx_storage) tx.weight = float('inf') data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) _input.data = P2PKH.create_input_data(public_bytes, signature) tx.update_hash() self.assertTrue(isinf(tx.weight)) with self.assertRaises(WeightError): tx.verify()
def test_unknown_authority(self): wallet = self.manager.wallet tx = create_tokens(self.manager, self.address_b58, mint_amount=500) token_uid = tx.tokens[0] parents = self.manager.get_new_tx_parents() script = P2PKH.create_output_script(self.address) # try an unknown authority input1 = TxInput(tx.hash, 1, b'') input2 = TxInput(tx.hash, 2, b'') output = TxOutput((TxOutput.ALL_AUTHORITIES << 1), script, 0b10000001) tx2 = Transaction(weight=1, inputs=[input1, input2], outputs=[output], parents=parents, tokens=[token_uid], storage=self.manager.tx_storage, timestamp=int(self.clock.seconds())) data_to_sign = tx2.get_sighash_all() public_bytes, signature = wallet.get_input_aux_data( data_to_sign, wallet.get_private_key(self.address_b58)) data = P2PKH.create_input_data(public_bytes, signature) tx2.inputs[0].data = data tx2.inputs[1].data = data tx2.resolve() with self.assertRaises(InvalidToken): tx2.verify()
def test_script(self): genesis_block = self.genesis_blocks[0] # random keys to be used random_priv = 'MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgMnAHVIyj7Hym2yI' \ 'w+JcKEfdCHByIp+FHfPoIkcnjqGyhRANCAATX76SGshGeoacUcZDhXEzERt' \ 'AHbd30CVpUg8RRnAIhaFcuMY3G+YFr/mReAPRuiLKCnolWz3kCltTtNj36rJyd' private_key_random = get_private_key_from_bytes( base64.b64decode(random_priv)) # create input data with incorrect private key _input = TxInput(genesis_block.hash, 0, b'') value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) tx = Transaction(inputs=[_input], outputs=[output], storage=self.tx_storage, timestamp=self.last_block.timestamp + 1) data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, private_key_random) data_wrong = P2PKH.create_input_data(public_bytes, signature) _input.data = data_wrong with self.assertRaises(InvalidInputData): tx.verify_inputs()
def test_tx_inputs_conflict(self): # the new tx inputs will try to spend the same output parents = [tx.hash for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) # We can't only duplicate the value because genesis is using the max value possible outputs = [TxOutput(value, script), TxOutput(value, script)] _input = TxInput(genesis_block.hash, 0, b'') tx = Transaction(weight=1, inputs=[_input, _input], outputs=outputs, parents=parents, storage=self.tx_storage, timestamp=self.last_block.timestamp + 1) data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) _input.data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() with self.assertRaises(ConflictingInputs): tx.verify()
def test_output_value(self): from hathor.transaction.base_transaction import bytes_to_output_value # first test using a small output value with 8 bytes. It should fail parents = [tx.hash for tx in self.genesis_txs] outputs = [TxOutput(1, b'')] tx = Transaction(outputs=outputs, parents=parents) original_struct = tx.get_struct() struct_bytes = tx.get_funds_struct() # we'll get the struct without the last output bytes and add it ourselves struct_bytes = struct_bytes[:-7] # add small value using 8 bytes and expect failure when trying to deserialize struct_bytes += (-1).to_bytes(8, byteorder='big', signed=True) struct_bytes += int_to_bytes(0, 1) struct_bytes += int_to_bytes(0, 2) struct_bytes += tx.get_graph_struct() struct_bytes += int_to_bytes(tx.nonce, tx.SERIALIZATION_NONCE_SIZE) len_difference = len(struct_bytes) - len(original_struct) assert len_difference == 4, 'new struct is incorrect, len difference={}'.format(len_difference) with self.assertRaises(ValueError): Transaction.create_from_struct(struct_bytes) # now use 8 bytes and make sure it's working outputs = [TxOutput(MAX_OUTPUT_VALUE, b'')] tx = Transaction(outputs=outputs, parents=parents) tx.update_hash() original_struct = tx.get_struct() tx2 = Transaction.create_from_struct(original_struct) tx2.update_hash() assert tx == tx2 # Validating that all output values must be positive value = 1 address = decode_address('WUDtnw3GYjvUnZmiHAmus6hhs9GoSUSJMG') script = P2PKH.create_output_script(address) output = TxOutput(value, script) output.value = -1 tx = Transaction(inputs=[], outputs=[output], parents=parents, storage=self.tx_storage) with self.assertRaises(InvalidOutputValue): tx.resolve() # 'Manually resolving', to validate verify method tx.hash = bytes.fromhex('012cba011be3c29f1c406f9015e42698b97169dbc6652d1f5e4d5c5e83138858') with self.assertRaises(InvalidOutputValue): tx.verify() # Invalid output value invalid_output = bytes.fromhex('ffffffff') with self.assertRaises(InvalidOutputValue): bytes_to_output_value(invalid_output) # Can't instantiate an output with negative value with self.assertRaises(AssertionError): TxOutput(-1, script)
def test_output_sum_ignore_authority(self): # sum of tx outputs should ignore authority outputs address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output1 = TxOutput(5, script) # regular utxo output2 = TxOutput(30, script, 0b10000001) # authority utxo output3 = TxOutput(3, script) # regular utxo tx = Transaction(outputs=[output1, output2, output3], storage=self.tx_storage) self.assertEqual(8, tx.sum_outputs)
def get_genesis_output(): # use this if to calculate the genesis output. We have to do it if: # - we change genesis priv/pub keys # - there's some change to the way we calculate hathor addresses from hathor.transaction.scripts import P2PKH from hathor.crypto.util import get_address_from_public_key # read genesis keys genesis_private_key = get_genesis_key() address = get_address_from_public_key(genesis_private_key.public_key()) return P2PKH.create_output_script(address).hex()
def render_POST(self, request): """ Creates a nano contract tx and returns it in hexadecimal format. Post data should be a json with the following items: values: List[{'address', 'value'}], with bet address and value fallback_address: if none of the addresses above is the winner, this address can execute the contract oracle_pubkey_hash: oracle's public key hashed oracle_data_id: oracle's id about this nano contract total_value: nano contract total value input_value: amount this wallet should stake in the nano contract :rtype: string (json) """ request.setHeader(b'content-type', b'application/json; charset=utf-8') set_cors(request, 'POST') try: data = json.loads(request.content.read().decode('utf-8')) except json.JSONDecodeError: return json.dumps({'success': False, 'message': 'Invalid format for post data'}).encode('utf-8') for param in PARAMS_POST: if param not in data: return get_missing_params_msg(param) try: decoded_params = self.decode_post_params(data) except ValueError as e: return json.dumps({'success': False, 'message': e.message}).encode('utf-8') nano_contract = NanoContractMatchValues( decoded_params.oracle_pubkey_hash, decoded_params.min_timestamp, decoded_params.oracle_data_id, decoded_params.value_dict, decoded_params.fallback_address ) tx_outputs = [] tx_outputs.append(TxOutput(decoded_params.total_value, nano_contract.create_output_script())) inputs, total_inputs_amount = self.manager.wallet.get_inputs_from_amount( decoded_params.input_value, self.manager.tx_storage ) change_tx = self.manager.wallet.handle_change_tx(total_inputs_amount, decoded_params.input_value) if change_tx: tx_outputs.append(TxOutput(change_tx.value, P2PKH.create_output_script(change_tx.address))) tx_inputs = [TxInput(txin.tx_id, txin.index, b'') for txin in inputs] tx = Transaction(inputs=tx_inputs, outputs=tx_outputs) ret = {'success': True, 'hex_tx': tx.get_struct().hex()} return json.dumps(ret).encode('utf-8')
def test_sighash_data_cache(self): from unittest import mock address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(5, script) tx = Transaction(outputs=[output], storage=self.tx_storage) with mock.patch('hathor.transaction.transaction.hashlib') as mocked: for _ in range(10): tx.get_sighash_all_data() mocked.sha256.assert_called_once()
def test_sigops_input_single_below_limit(self) -> None: genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value - 1 address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) _output = TxOutput(value, script) hscript = create_script_with_sigops(settings.MAX_TX_SIGOPS_INPUT - 1) input3 = TxInput(genesis_block.hash, 0, hscript) tx = Transaction(inputs=[input3], outputs=[_output], storage=self.tx_storage) tx.update_hash() tx.verify_sigops_input()
def test_tx_token_outputs(self): genesis_block = self.genesis_blocks[0] _input = TxInput(genesis_block.hash, 0, b'') value = genesis_block.outputs[0].value script = P2PKH.create_output_script(self.address) output = TxOutput(value, script, 1) parents = [tx.hash for tx in self.genesis_txs] tx = Transaction(weight=1, inputs=[_input], outputs=[output], parents=parents, storage=self.manager.tx_storage) # no token uids in list data_to_sign = tx.get_sighash_all() public_bytes, signature = self.manager.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) tx.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() with self.assertRaises(InvalidToken): tx.verify() # with 1 token uid in list tx.tokens = [ bytes.fromhex( '0023be91834c973d6a6ddd1a0ae411807b7c8ef2a015afb5177ee64b666ce602' ) ] output.token_data = 2 data_to_sign = tx.get_sighash_all() public_bytes, signature = self.manager.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) tx.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() with self.assertRaises(InvalidToken): tx.verify() # try hathor authority UTXO output = TxOutput(value, script, 0b10000000) tx.outputs = [output] data_to_sign = tx.get_sighash_all() public_bytes, signature = self.manager.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) tx.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() with self.assertRaises(InvalidToken): tx.verify()
def get_genesis_output(): import base58 from hathor.transaction.scripts import P2PKH if settings.NETWORK_NAME == 'mainnet': address = 'HJB2yxxsHtudGGy3jmVeadwMfRi2zNCKKD' elif settings.NETWORK_NAME.startswith('testnet'): address = 'WdmDUMp8KvzhWB7KLgguA2wBiKsh4Ha8eX' elif settings.NETWORK_NAME == 'unittests': address = 'HVayMofEDh4XGsaQJeRJKhutYxYodYNop6' else: raise ValueError('Network unknown.') address_bytes = base58.b58decode(address) return P2PKH.create_output_script(address_bytes).hex()
def test_sigops_input_single_above_limit(self) -> None: genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value - 1 address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) _output = TxOutput(value, script) hscript = create_script_with_sigops(settings.MAX_TX_SIGOPS_INPUT + 1) input1 = TxInput(genesis_block.hash, 0, hscript) tx = Transaction(inputs=[input1], outputs=[_output], storage=self.tx_storage) tx.update_hash() with self.assertRaises(TooManySigOps): tx.verify()
def test_tx_inputs_out_of_range(self): # we'll try to spend output 3 from genesis transaction, which does not exist parents = [tx.hash for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) _input = TxInput(genesis_block.hash, len(genesis_block.outputs) + 1, b'') tx = Transaction(weight=1, inputs=[_input], outputs=[output], parents=parents, storage=self.tx_storage) data_to_sign = tx.get_sighash_all() public_bytes, signature = self.wallet.get_input_aux_data( data_to_sign, self.genesis_private_key) data = P2PKH.create_input_data(public_bytes, signature) tx.inputs[0].data = data # test with an inexistent index tx.resolve() with self.assertRaises(InexistentInput): tx.verify() # now with index equals of len of outputs _input = [ TxInput(genesis_block.hash, len(genesis_block.outputs), data) ] tx.inputs = _input # test with an inexistent index tx.resolve() with self.assertRaises(InexistentInput): tx.verify() # now with inexistent tx hash random_bytes = bytes.fromhex( '0000184e64683b966b4268f387c269915cc61f6af5329823a93e3696cb0fe902') _input = [TxInput(random_bytes, 3, data)] tx.inputs = _input tx.resolve() with self.assertRaises(InexistentInput): tx.verify()
def test_tokens_balance(self): # create tokens and check balances # initial tokens address_b58 = self.manager.wallet.get_unused_address() address = decode_address(address_b58) tx = create_tokens(self.manager, address_b58) token_id = tx.tokens[0] amount = tx.outputs[0].value # initial token balance self.assertEqual(self.manager.wallet.balance[token_id], WalletBalance(0, amount)) # initial hathor balance # we don't consider HTR balance 0 because we transfer genesis tokens to this # wallet during token creation hathor_balance = self.manager.wallet.balance[settings.HATHOR_TOKEN_UID] # transfer token to another wallet and check balance again parents = self.manager.get_new_tx_parents() _input1 = TxInput(tx.hash, 0, b'') script = P2PKH.create_output_script(address) token_output1 = TxOutput(30, b'', 0b00000001) token_output2 = TxOutput(amount - 30, script, 0b00000001) tx2 = Transaction(weight=1, inputs=[_input1], outputs=[token_output1, token_output2], parents=parents, tokens=[token_id], storage=self.manager.tx_storage, timestamp=int(self.manager.reactor.seconds())) data_to_sign = tx2.get_sighash_all(clear_input_data=True) public_bytes, signature = self.manager.wallet.get_input_aux_data( data_to_sign, self.manager.wallet.get_private_key(address_b58)) tx2.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx2.resolve() tx2.verify() self.manager.propagate_tx(tx2) self.run_to_completion() # verify balance self.assertEqual(self.manager.wallet.balance[token_id], WalletBalance(0, amount - 30)) # hathor balance remains the same self.assertEqual( self.manager.wallet.balance[settings.HATHOR_TOKEN_UID], hathor_balance)
def test_tokens_in_block(self): # a block with token index > 1 should be invalid parents = [tx.hash for tx in self.genesis] output_script = P2PKH.create_output_script(self.address) tx_outputs = [TxOutput(100, output_script, 1)] block = Block( nonce=100, outputs=tx_outputs, parents=parents, weight=1, # low weight so we don't waste time with PoW storage=self.manager.tx_storage) block.resolve() with self.assertRaises(BlockWithTokensError): block.verify()
def test_block_with_htr_authority(self): parents = [tx.hash for tx in self.genesis] output_script = P2PKH.create_output_script(self.address) output = TxOutput(0b11, output_script, 0b10000000) self.assertTrue(output.is_token_authority()) block = Block( nonce=100, outputs=[output], parents=parents, weight=1, # low weight so we don't waste time with PoW storage=self.manager.tx_storage) block.resolve() with self.assertRaises(InvalidToken): block.verify()
def test_block_number_parents(self): address = get_address_from_public_key(self.genesis_public_key) output_script = P2PKH.create_output_script(address) tx_outputs = [TxOutput(100, output_script)] parents = [tx.hash for tx in self.genesis_txs] block = Block( nonce=100, outputs=tx_outputs, parents=parents, weight=1, # low weight so we don't waste time with PoW storage=self.tx_storage) block.resolve() with self.assertRaises(IncorrectParents): block.verify()
def test_input_output_match(self): genesis_block = self.genesis_blocks[0] _input = TxInput(genesis_block.hash, 0, b'') # spend less than what was generated value = genesis_block.outputs[0].value - 1 address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) tx = Transaction(inputs=[_input], outputs=[output], storage=self.tx_storage) data_to_sign = tx.get_sighash_all(clear_input_data=True) public_bytes, signature = self.wallet.get_input_aux_data(data_to_sign, self.genesis_private_key) _input.data = P2PKH.create_input_data(public_bytes, signature) with self.assertRaises(InputOutputMismatch): tx.verify_sum()
def test_block_unknown_parent(self): address = get_address_from_public_key(self.genesis_public_key) output_script = P2PKH.create_output_script(address) tx_outputs = [TxOutput(100, output_script)] # Random unknown parent parents = [hashlib.sha256().digest()] block = Block( nonce=100, outputs=tx_outputs, parents=parents, weight=1, # low weight so we don't waste time with PoW storage=self.tx_storage) block.resolve() with self.assertRaises(ParentDoesNotExist): block.verify()
def _gen_tx_spending_genesis_block(self): parents = [tx.hash for tx in self.genesis_txs] genesis_block = self.genesis_blocks[0] _input = TxInput(genesis_block.hash, 0, b'') value = genesis_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) output = TxOutput(value, script) tx = Transaction(nonce=100, inputs=[_input], outputs=[output], parents=parents, storage=self.tx_storage) data_to_sign = tx.get_sighash_all(clear_input_data=True) public_bytes, signature = self.wallet.get_input_aux_data(data_to_sign, self.genesis_private_key) tx.inputs[0].data = P2PKH.create_input_data(public_bytes, signature) tx.update_hash() return tx
def test_block_outputs(self): from hathor.transaction import MAX_NUM_OUTPUTS from hathor.transaction.exceptions import TooManyOutputs # a block should have no more than MAX_NUM_OUTPUTS outputs parents = [tx.hash for tx in self.genesis] address = get_address_from_public_key(self.genesis_public_key) output_script = P2PKH.create_output_script(address) tx_outputs = [TxOutput(100, output_script)] * (MAX_NUM_OUTPUTS + 1) block = Block( nonce=100, outputs=tx_outputs, parents=parents, weight=1, # low weight so we don't waste time with PoW storage=self.tx_storage) with self.assertRaises(TooManyOutputs): block.verify_outputs()
def _spend_reward_tx(self, manager, reward_block): value = reward_block.outputs[0].value address = get_address_from_public_key(self.genesis_public_key) script = P2PKH.create_output_script(address) input_ = TxInput(reward_block.hash, 0, b'') output = TxOutput(value, script) tx = Transaction( weight=1, timestamp=int(manager.reactor.seconds()) + 1, inputs=[input_], outputs=[output], parents=manager.get_new_tx_parents(), storage=manager.tx_storage, ) data_to_sign = tx.get_sighash_all(clear_input_data=True) public_bytes, signature = self.wallet.get_input_aux_data(data_to_sign, self.genesis_private_key) input_.data = P2PKH.create_input_data(public_bytes, signature) tx.resolve() return tx