示例#1
0
    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)
示例#2
0
    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())
示例#3
0
    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()
示例#4
0
    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
示例#5
0
    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)
示例#6
0
    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
示例#7
0
    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()
示例#8
0
    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()
示例#9
0
 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
示例#10
0
    def test_too_many_inputs(self):
        random_bytes = bytes.fromhex('0000184e64683b966b4268f387c269915cc61f6af5329823a93e3696cb0fe902')

        _input = TxInput(random_bytes, 0, random_bytes)
        inputs = [_input] * (MAX_NUM_INPUTS + 1)

        tx = Transaction(inputs=inputs, storage=self.tx_storage)

        with self.assertRaises(TooManyInputs):
            tx.verify_number_of_inputs()
示例#11
0
    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()
        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()
        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()
示例#12
0
    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(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()
        tx.verify()
示例#13
0
    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()
示例#14
0
    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()
示例#15
0
    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(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()
        with self.assertRaises(DuplicatedParents):
            tx.verify()
示例#16
0
    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')
示例#17
0
    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)
示例#18
0
    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(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()
        with self.assertRaises(ConflictingInputs):
            tx.verify()
示例#19
0
    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(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.update_hash()
        self.assertTrue(isinf(tx.weight))
        with self.assertRaises(WeightError):
            tx.verify()
示例#20
0
    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()
示例#21
0
    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()
示例#22
0
    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()
示例#23
0
        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()
示例#24
0
    def render_POST(self, request):
        """ Post request /create_tx/ that returns an encoded tx, if valid

            Expects {"inputs":[{"tx_id": <hex encoded>, "index": <int>, "data": <optional base64 encoded>}],
                     "outputs":[{"value": <int, 1.00 HTR = 100>, "token_uid": <optional omit for HTR, hex encoded>,
                     "address" or "script"}]} as POST data
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'POST')

        body_content = json_loadb(request.content.read())

        raw_inputs = body_content.get('inputs', [])
        raw_outputs = body_content.get('outputs', [])

        inputs = [TxInput.create_from_dict(i) for i in raw_inputs]
        tokens = []
        outputs = [from_raw_output(i, tokens) for i in raw_outputs]

        timestamp = int(max(self.manager.tx_storage.latest_timestamp, self.manager.reactor.seconds()))
        parents = self.manager.get_new_tx_parents(timestamp)
        # this tx will have to be mined by tx-mining-server or equivalent
        tx = Transaction(
            timestamp=timestamp,
            inputs=inputs,
            outputs=outputs,
            parents=parents,
            storage=self.manager.tx_storage,
        )
        fake_signed_tx = tx.clone()
        for tx_input in fake_signed_tx.inputs:
            # conservative estimate of the input data size to estimate a valid weight
            tx_input.data = b'\0' * 107
        tx.weight = minimum_tx_weight(fake_signed_tx)
        tx.verify_unsigned_skip_pow()

        if tx.is_double_spending():
            raise InvalidNewTransaction('At least one of your inputs has already been spent.')

        hex_data = bytes(tx).hex()
        data = tx.to_json()
        data.pop('hash', None)
        data.pop('nonce', None)

        return json_dumpb({
            'success': True,
            'hex_data': hex_data,
            'data': data,
        })
示例#25
0
    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()
示例#26
0
    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()
示例#27
0
    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_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)
示例#29
0
    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
示例#30
0
    def test_tx_number_parents(self):
        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)

        parents = [self.genesis_txs[0].hash]
        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)
        tx.inputs[0].data = P2PKH.create_input_data(public_bytes, signature)

        # in first test, only with 1 parent
        tx.resolve()
        with self.assertRaises(IncorrectParents):
            tx.verify()

        # test with 3 parents
        parents = [tx.hash for tx in self.genesis]
        tx.parents = parents
        tx.resolve()
        with self.assertRaises(IncorrectParents):
            tx.verify()

        # 2 parents, 1 tx and 1 block
        parents = [self.genesis_txs[0].hash, self.genesis_blocks[0].hash]
        tx.parents = parents
        tx.resolve()
        with self.assertRaises(IncorrectParents):
            tx.verify()