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_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_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_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 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_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 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_propagation_error(self): manager = self.create_peer('testnet', unlock_wallet=True) manager.test_mode = TestMode.DISABLED # 1. propagate genesis genesis_block = self.genesis_blocks[0] genesis_block.storage = manager.tx_storage self.assertFalse(manager.propagate_tx(genesis_block)) # 2. propagate block with weight 1 block = manager.generate_mining_block() block.weight = 1 block.resolve() self.assertFalse(manager.propagate_tx(block)) # 3. propagate block with wrong amount of tokens block = manager.generate_mining_block() output = TxOutput(1, block.outputs[0].script) block.outputs = [output] block.resolve() self.assertFalse(manager.propagate_tx(block)) # 4. propagate block from the future block = manager.generate_mining_block() block.timestamp = int( self.clock.seconds()) + settings.MAX_FUTURE_TIMESTAMP_ALLOWED + 100 block.resolve(update_time=False) self.assertFalse(manager.propagate_tx(block))
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_checkdatasig_raise_on_uncompressed_pubkey(self): block = self.genesis_blocks[0] data = b'some_random_data' from hathor.transaction import Transaction, TxInput, TxOutput txin = TxInput(tx_id=block.hash, index=0, data=b'') txout = TxOutput(value=block.outputs[0].value, script=b'') tx = Transaction(inputs=[txin], outputs=[txout]) import hashlib data_to_sign = tx.get_sighash_all() hashed_data = hashlib.sha256(data_to_sign).digest() signature = self.genesis_private_key.sign(hashed_data, ec.ECDSA(hashes.SHA256())) from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat pubkey_uncompressed = self.genesis_public_key.public_bytes( Encoding.X962, PublicFormat.UncompressedPoint) # ScriptError if pubkey is not a valid compressed public key # with wrong signature stack = [data, b'123', pubkey_uncompressed] with self.assertRaises(ScriptError): op_checkdatasig(stack, log=[], extras=None) # or with rigth one # this will make sure the signature is not made when parameters are wrong stack = [data, signature, pubkey_uncompressed] with self.assertRaises(ScriptError): op_checkdatasig(stack, log=[], extras=None)
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_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_checksig(self): with self.assertRaises(MissingStackItems): op_checksig([1], log=[], extras=None) block = self.genesis_blocks[0] from hathor.transaction import Transaction, TxInput, TxOutput txin = TxInput(tx_id=block.hash, index=0, data=b'') txout = TxOutput(value=block.outputs[0].value, script=b'') tx = Transaction(inputs=[txin], outputs=[txout]) import hashlib data_to_sign = tx.get_sighash_all() hashed_data = hashlib.sha256(data_to_sign).digest() signature = self.genesis_private_key.sign(hashed_data, ec.ECDSA(hashes.SHA256())) pubkey_bytes = get_public_key_bytes_compressed(self.genesis_public_key) extras = ScriptExtras(tx=tx, txin=None, spent_tx=None) # wrong signature puts False (0) on stack stack = [b'aaaaaaaaa', pubkey_bytes] op_checksig(stack, log=[], extras=extras) self.assertEqual(0, stack.pop()) stack = [signature, pubkey_bytes] op_checksig(stack, log=[], extras=extras) self.assertEqual(1, stack.pop())
def prepare_transaction(self, cls: ABCMeta, inputs: List[WalletInputInfo], outputs: List[WalletOutputInfo], timestamp: Optional[int] = None) -> Transaction: """Prepares the tx inputs and outputs. Can be used to create blocks by passing empty list to inputs. :param cls: defines if we're creating a Transaction or Block :type cls: :py:class:`hathor.transaction.Block` or :py:class:`hathor.transaction.Transaction` :param inputs: the tx inputs :type inputs: List[WalletInputInfo] :param outputs: the tx outputs :type inputs: List[WalletOutputInfo] :param timestamp: timestamp to use for the transaction :type timestamp: int """ tx_outputs = [] token_dict: Dict[bytes, int] = {} # Dict[token_uid, index] tokens = [] # List[bytes] = List[token_uid] for txout in outputs: token_uid = bytes.fromhex(txout.token_uid) if token_uid == settings.HATHOR_TOKEN_UID: token_index = 0 elif token_uid in token_dict: token_index = token_dict[token_uid] else: tokens.append(token_uid) token_index = len(tokens) token_dict[token_uid] = token_index timelock = int_to_bytes(txout.timelock, 4) if txout.timelock else None tx_outputs.append( TxOutput(txout.value, create_output_script(txout.address, timelock), token_index)) tx_inputs = [] private_keys = [] for wtxin in inputs: private_keys.append(wtxin.private_key) tx_inputs.append(TxInput(wtxin.tx_id, wtxin.index, b'')) tx = cls(inputs=tx_inputs, outputs=tx_outputs, tokens=tokens, timestamp=timestamp) data_to_sign = tx.get_sighash_all(clear_input_data=True) for txin, privkey in zip(tx.inputs, private_keys): public_key_bytes, signature = self.get_input_aux_data( data_to_sign, privkey) txin.data = P2PKH.create_input_data(public_key_bytes, signature) return tx
def get_funds_fields_from_struct(self, buf: bytes) -> bytes: """ Gets all funds fields for a transaction from a buffer. :param buf: Bytes of a serialized transaction :type buf: bytes :return: A buffer containing the remaining struct bytes :rtype: bytes :raises ValueError: when the sequence of bytes is incorect """ (self.version, tokens_len, inputs_len, outputs_len), buf = unpack(_FUNDS_FORMAT_STRING, buf) for _ in range(tokens_len): token_uid, buf = unpack_len(TX_HASH_SIZE, buf) self.tokens.append(token_uid) for _ in range(inputs_len): txin, buf = TxInput.create_from_bytes(buf) self.inputs.append(txin) for _ in range(outputs_len): txout, buf = TxOutput.create_from_bytes(buf) self.outputs.append(txout) return buf
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_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_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_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 generate_minimaly_valid_block(self) -> BaseTransaction: """ Generates a block, without any extra information that is valid for this template. No random choices.""" from hathor.transaction import TxOutput, TxVersion return TxVersion(min(self.versions)).get_cls()( timestamp=self.timestamp_min, parents=self.parents[:] + sorted(self.parents_any)[:(3 - len(self.parents))], outputs=[TxOutput(self.reward, b'')], weight=self.weight, )
def test_too_many_outputs(self): random_bytes = bytes.fromhex('0000184e64683b966b4268f387c269915cc61f6af5329823a93e3696cb0fe902') output = TxOutput(1, random_bytes) outputs = [output] * (MAX_NUM_OUTPUTS + 1) tx = Transaction(outputs=outputs, storage=self.tx_storage) with self.assertRaises(TooManyOutputs): tx.verify_number_of_outputs()
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_txout_script_limit(self, offset): genesis_block = self.genesis_blocks[0] _input = TxInput(genesis_block.hash, 0, b'') value = genesis_block.outputs[0].value script = b'*' * (settings.MAX_OUTPUT_SCRIPT_SIZE + offset) _output = TxOutput(value, script) tx = Transaction(inputs=[_input], outputs=[_output], storage=self.tx_storage) tx.verify_outputs()
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_txin_data_limit(self, offset): genesis_block = self.genesis_blocks[0] data = b'*' * (settings.MAX_INPUT_DATA_SIZE + offset) _input = TxInput(genesis_block.hash, 0, data) value = genesis_block.outputs[0].value _output = TxOutput(value, b'') tx = Transaction(timestamp=int(self.manager.reactor.seconds()) + 1, inputs=[_input], outputs=[_output], storage=self.tx_storage) tx.verify_inputs(skip_script=True)
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 setUp(self, tx_storage, reactor=None): if not reactor: self.reactor = Clock() else: self.reactor = reactor self.reactor.advance(time.time()) self.tx_storage = tx_storage assert tx_storage.first_timestamp > 0 tx_storage._manually_initialize() self.genesis = self.tx_storage.get_all_genesis() self.genesis_blocks = [tx for tx in self.genesis if tx.is_block] self.genesis_txs = [tx for tx in self.genesis if not tx.is_block] from hathor.manager import HathorManager self.tmpdir = tempfile.mkdtemp() wallet = Wallet(directory=self.tmpdir) wallet.unlock(b'teste') self.manager = HathorManager(self.reactor, tx_storage=self.tx_storage, wallet=wallet) self.tx_storage.wallet_index = WalletIndex(self.manager.pubsub) self.tx_storage.tokens_index = TokensIndex() block_parents = [tx.hash for tx in chain(self.genesis_blocks, self.genesis_txs)] output = TxOutput(200, bytes.fromhex('1e393a5ce2ff1c98d4ff6892f2175100f2dad049')) self.block = Block(timestamp=MIN_TIMESTAMP, weight=12, outputs=[output], parents=block_parents, nonce=100781, storage=tx_storage) self.block.resolve() self.block.verify() tx_parents = [tx.hash for tx in self.genesis_txs] tx_input = TxInput( tx_id=self.genesis_blocks[0].hash, index=0, data=bytes.fromhex('46304402203470cb9818c9eb842b0c433b7e2b8aded0a51f5903e971649e870763d0266a' 'd2022049b48e09e718c4b66a0f3178ef92e4d60ee333d2d0e25af8868acf5acbb35aaa583' '056301006072a8648ce3d020106052b8104000a034200042ce7b94cba00b654d4308f8840' '7345cacb1f1032fb5ac80407b74d56ed82fb36467cb7048f79b90b1cf721de57e942c5748' '620e78362cf2d908e9057ac235a63')) self.tx = Transaction( timestamp=MIN_TIMESTAMP + 2, weight=10, nonce=932049, inputs=[tx_input], outputs=[output], tokens=[bytes.fromhex('0023be91834c973d6a6ddd1a0ae411807b7c8ef2a015afb5177ee64b666ce602')], parents=tx_parents, storage=tx_storage) self.tx.resolve() # Disable weakref to test the internal methods. Otherwise, most methods return objects from weakref. self.tx_storage._disable_weakref() self.tx_storage.enable_lock()
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()