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_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 _render_POST_thread(self, tx: Transaction, request: Request) -> Transaction: """ Method called in a thread to solve tx pow without stratum """ # TODO Tx should be resolved in the frontend def _should_stop(): return request.should_stop_mining_thread tx.start_mining(sleep_seconds=self.sleep_seconds, should_stop=_should_stop) if request.should_stop_mining_thread: raise CancelledError() tx.update_hash() tx.verify() return tx
def test_sigops_output_single_below_limit(self) -> None: genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value - 1 _input = TxInput(genesis_block.hash, 0, b'') hscript = create_script_with_sigops(settings.MAX_TX_SIGOPS_OUTPUT - 1) output3 = TxOutput(value, hscript) tx = Transaction(inputs=[_input], outputs=[output3], storage=self.tx_storage) tx.update_hash() tx.verify_sigops_output()
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_sigops_output_single_above_limit(self) -> None: genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value - 1 _input = TxInput(genesis_block.hash, 0, b'') hscript = create_script_with_sigops(settings.MAX_TX_SIGOPS_OUTPUT + 1) output1 = TxOutput(value, hscript) tx = Transaction(inputs=[_input], outputs=[output1], storage=self.tx_storage) tx.update_hash() # This calls verify to ensure that verify_sigops_output is being called on verify with self.assertRaises(TooManySigOps): tx.verify()
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_sigops_output_multi_above_limit(self) -> None: genesis_block = self.genesis_blocks[0] value = genesis_block.outputs[0].value - 1 _input = TxInput(genesis_block.hash, 0, b'') num_outputs = 5 hscript = create_script_with_sigops( (settings.MAX_TX_SIGOPS_OUTPUT + num_outputs) // num_outputs) output2 = TxOutput(value, hscript) tx = Transaction(inputs=[_input], outputs=[output2] * num_outputs, storage=self.tx_storage) tx.update_hash() with self.assertRaises(TooManySigOps): tx.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 _get_new_tx(self, nonce): tx = Transaction(nonce=nonce, storage=self.cache_storage) tx.update_hash() meta = TransactionMetadata(hash=tx.hash) tx._metadata = meta return tx