def deprecated_resource(self, request: Request) -> bytes:
        """ This resource is deprecated. It's here only to keep
            compatibility with old wallet versions
        """
        if b'addresses[]' not in request.args:
            return get_missing_params_msg('addresses[]')

        addresses = request.args[b'addresses[]']
        history = []
        seen: Set[bytes] = set()
        for address_to_decode in addresses:
            address = address_to_decode.decode('utf-8')
            try:
                decode_address(address)
            except InvalidAddress:
                return json.dumps({
                    'success':
                    False,
                    'message':
                    'The address {} is invalid'.format(address)
                }).encode('utf-8')

            for tx_hash in self.manager.tx_storage.wallet_index.get_from_address(
                    address):
                tx = self.manager.tx_storage.get_transaction(tx_hash)
                if tx_hash not in seen:
                    seen.add(tx_hash)
                    history.append(tx.to_json_extended())

        data = {'history': history}
        return json.dumps(data, indent=4).encode('utf-8')
Beispiel #2
0
    def get_tx(
            self,
            inputs: Optional[List[WalletInputInfo]] = None,
            outputs: Optional[List[WalletOutputInfo]] = None) -> Transaction:
        if not outputs:
            address = self.get_address(0)
            assert address is not None
            outputs = [
                WalletOutputInfo(address=decode_address(address),
                                 value=1,
                                 timelock=None),
                WalletOutputInfo(address=decode_address(address),
                                 value=1,
                                 timelock=None)
            ]
        if inputs:
            tx = self.manager.wallet.prepare_transaction(
                Transaction, inputs, outputs)
        else:
            tx = self.manager.wallet.prepare_transaction_compute_inputs(
                Transaction, outputs, self.manager.tx_storage)

        tx.storage = self.manager.tx_storage
        tx.weight = 1
        max_ts_spent_tx = max(
            tx.get_spent_tx(txin).timestamp for txin in tx.inputs)
        tx.timestamp = max(max_ts_spent_tx + 1,
                           int(self.manager.reactor.seconds()))
        tx.parents = self.manager.get_new_tx_parents(tx.timestamp)
        tx.resolve()
        return tx
Beispiel #3
0
def gen_custom_tx(manager: HathorManager, tx_inputs: List[Tuple[Transaction, int]], *, n_outputs: int = 1,
                  base_parent: Optional[Transaction] = None, weight: Optional[float] = None) -> Transaction:
    """Generate a custom tx based on the inputs and outputs. It gives full control to the
    inputs and can be used to generate conflicts and specific patterns in the DAG."""
    inputs = []
    value = 0
    parents = []
    for tx_base, txout_index in tx_inputs:
        assert tx_base.hash is not None
        spent_tx = tx_base
        spent_txout = spent_tx.outputs[txout_index]
        p2pkh = parse_address_script(spent_txout.script)
        assert isinstance(p2pkh, P2PKH)

        from hathor.wallet.base_wallet import WalletInputInfo, WalletOutputInfo
        value += spent_txout.value
        wallet = manager.wallet
        assert wallet is not None
        assert spent_tx.hash is not None
        private_key = wallet.get_private_key(p2pkh.address)
        inputs.append(WalletInputInfo(tx_id=spent_tx.hash, index=txout_index, private_key=private_key))
        if not tx_base.is_block:
            parents.append(tx_base.hash)

    assert wallet is not None
    address = wallet.get_unused_address(mark_as_used=True)
    if n_outputs == 1:
        outputs = [WalletOutputInfo(address=decode_address(address), value=int(value), timelock=None)]
    elif n_outputs == 2:
        assert int(value) > 1
        outputs = [
            WalletOutputInfo(address=decode_address(address), value=int(value) - 1, timelock=None),
            WalletOutputInfo(address=decode_address(address), value=1, timelock=None),
        ]
    else:
        raise NotImplementedError

    tx2 = wallet.prepare_transaction(Transaction, inputs, outputs)
    tx2.storage = manager.tx_storage
    tx2.timestamp = max(tx_base.timestamp + 1, int(manager.reactor.seconds()))

    tx2.parents = parents[:2]
    if len(tx2.parents) < 2:
        if base_parent:
            assert base_parent.hash is not None
            tx2.parents.append(base_parent.hash)
        elif not tx_base.is_block:
            tx2.parents.append(tx_base.parents[0])
        else:
            tx2.parents.extend(manager.get_new_tx_parents(tx2.timestamp))
            tx2.parents = tx2.parents[:2]
    assert len(tx2.parents) == 2

    tx2.weight = weight or 25
    tx2.update_hash()
    return tx2
Beispiel #4
0
    def test_choose_inputs(self):
        blocks = add_new_blocks(self.manager, 1, advance_clock=15)
        blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]
        add_blocks_unlock_reward(self.manager)

        address = self.manager.wallet.get_unused_address(mark_as_used=False)

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=blocks_tokens[0],
                             timelock=int(self.clock.seconds()) + 10)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()
        self.manager.propagate_tx(tx1)
        self.clock.advance(1)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(blocks_tokens[0], 0))

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=blocks_tokens[0],
                             timelock=None)
        ]

        with self.assertRaises(InsufficientFunds):
            self.manager.wallet.prepare_transaction_compute_inputs(
                Transaction, outputs, self.manager.tx_storage)

        self.clock.advance(10)

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx2.weight = 10
        tx2.parents = self.manager.get_new_tx_parents()
        tx2.timestamp = int(self.clock.seconds())
        tx2.resolve()
        self.manager.propagate_tx(tx2)

        self.assertEqual(
            self.manager.wallet.balance[settings.HATHOR_TOKEN_UID],
            WalletBalance(0, blocks_tokens[0]))
Beispiel #5
0
    def test_transaction_and_balance(self):
        # generate a new block and check if we increase balance
        new_address = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), self.TOKENS, timelock=None)
        block = add_new_block(self.manager)
        block.verify()
        utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get((block.hash, 0))
        self.assertIsNotNone(utxo)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.BLOCK_TOKENS))

        # create transaction spending this value, but sending to same wallet
        new_address2 = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address2), self.TOKENS, timelock=None)
        tx1 = self.wallet.prepare_transaction_compute_inputs(Transaction, outputs=[out])
        tx1.update_hash()
        tx1.verify_script(tx1.inputs[0], block)
        tx1.storage = self.tx_storage
        self.wallet.on_new_tx(tx1)
        self.tx_storage.save_transaction(tx1)
        self.assertEqual(len(self.wallet.spent_txs), 1)
        utxo = self.wallet.unspent_txs[settings.HATHOR_TOKEN_UID].get((tx1.hash, 0))
        self.assertIsNotNone(utxo)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS))

        # pass inputs and outputs to prepare_transaction, but not the input keys
        # spend output last transaction
        input_info = WalletInputInfo(tx1.hash, 0, None)
        new_address3 = self.wallet.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address3), self.TOKENS, timelock=None)
        tx2 = self.wallet.prepare_transaction_incomplete_inputs(Transaction, inputs=[input_info],
                                                                outputs=[out], tx_storage=self.tx_storage)
        tx2.storage = self.tx_storage
        tx2.update_hash()
        tx2.storage = self.tx_storage
        tx2.verify_script(tx2.inputs[0], tx1)
        self.tx_storage.save_transaction(tx2)
        self.wallet.on_new_tx(tx2)
        self.assertEqual(len(self.wallet.spent_txs), 2)
        self.assertEqual(self.wallet.balance[settings.HATHOR_TOKEN_UID], WalletBalance(0, self.TOKENS))

        # Test getting more unused addresses than the gap limit
        for i in range(3):
            kwargs = {'mark_as_used': True}
            if i == 2:
                # Last one we dont mark as used
                kwargs['mark_as_used'] = False

            self.wallet.get_unused_address(**kwargs)
Beispiel #6
0
    def decode_params(self, data: Dict[str, Any]) -> DecodedParams:
        """Decode the data required for execute operation. Raise an error if any of the
        fields is not of the expected type.
        """
        try:
            spent_tx_id = bytes.fromhex(data['spent_tx_id'])
        except ValueError:
            raise ValueError('Invalid \'spent_tx_id\' parameter')

        try:
            oracle_data = base64.b64decode(data['oracle_data'])
        except binascii.Error:
            raise ValueError('Invalid \'oracle_data\' parameter')

        try:
            oracle_signature = base64.b64decode(data['oracle_signature'])
        except binascii.Error:
            raise ValueError('Invalid \'oracle_signature\' parameter')

        try:
            oracle_pubkey = base64.b64decode(data['oracle_pubkey'])
        except binascii.Error:
            raise ValueError('Invalid \'oracle_pubkey\' parameter')

        try:
            address = decode_address(data['address'])
        except InvalidAddress:
            raise ValueError('Invalid \'address\' parameter')

        return DecodedParams(spent_tx_id, oracle_data, oracle_signature,
                             oracle_pubkey, address, data['spent_tx_index'],
                             data['value'])
Beispiel #7
0
    def handle_change_tx(
        self,
        sum_inputs: int,
        sum_outputs: int,
        token_uid: bytes = settings.HATHOR_TOKEN_UID
    ) -> Optional[WalletOutputInfo]:
        """Creates an output transaction with the change value

        :param sum_inputs: Sum of the input amounts
        :type sum_inputs: int

        :param sum_outputs: Total value we're spending
        :type outputs: int

        :param token_uid: token uid of this utxo
        :type token_uid: bytes

        :return: Return an output with the change
        :rtype: :py:class:`hathor.wallet.base_wallet.WalletOutputInfo`
        """
        if sum_inputs > sum_outputs:
            difference = sum_inputs - sum_outputs
            address_b58 = self.get_unused_address()
            address = decode_address(address_b58)
            # Changes txs don't have timelock
            new_output = WalletOutputInfo(address, difference, None,
                                          token_uid.hex())
            return new_output
        return None
Beispiel #8
0
    def render_GET(self, request):
        """ GET request /mining/
            Generates a new block to be mined with correct parents
            Returns a json with a list of parents hash and the block in bytes

            :rtype: string (json)
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')

        if not self.manager.can_start_mining():
            request.setResponseCode(503)
            return json.dumps({'reason': 'Node still syncing'}).encode('utf-8')

        address = None

        if b'address' in request.args:
            address_txt = request.args[b'address'][0].decode('utf-8')
            try:
                address = decode_address(address_txt)  # bytes
            except InvalidAddress:
                return json.dumps({
                    'success': False,
                    'message': 'Invalid address'
                }).encode('utf-8')

        block = self.manager.generate_mining_block(address=address)
        block_bytes = block.get_struct()

        data = {
            'parents': [x.hex() for x in block.parents],
            'block_bytes': base64.b64encode(block_bytes).decode('utf-8'),
        }
        return json.dumps(data, indent=4).encode('utf-8')
        def setUp(self):
            super().setUp()

            self.network = 'testnet'
            self.manager = self.create_peer(self.network, unlock_wallet=True)
            self.tx_storage = self.manager.tx_storage

            data = b'This is a test block.'
            self.blocks = add_new_blocks(self.manager, 3, advance_clock=15, block_data=data)

            address = self.get_address(0)
            value = 100

            outputs = [
                WalletOutputInfo(address=decode_address(address), value=int(value), timelock=None)
            ]

            self.tx1 = self.manager.wallet.prepare_transaction_compute_inputs(Transaction, outputs)
            self.tx1.weight = 10
            self.tx1.parents = self.manager.get_new_tx_parents()
            self.tx1.timestamp = int(self.clock.seconds())
            self.tx1.resolve()
            self.manager.propagate_tx(self.tx1)

            # Change of parents only, so it's a twin.
            # With less weight, so the balance will continue because tx1 will be the winner
            self.tx2 = Transaction.create_from_struct(self.tx1.get_struct())
            self.tx2.parents = [self.tx1.parents[1], self.tx1.parents[0]]
            self.tx2.weight = 9
            self.tx2.resolve()

            # Propagate a conflicting twin transaction
            self.manager.propagate_tx(self.tx2)
Beispiel #10
0
def gen_new_double_spending(manager: HathorManager, *, use_same_parents: bool = False) -> Transaction:
    tx_interval = random.choice(list(manager.tx_storage.get_tx_tips()))
    tx = manager.tx_storage.get_transaction(tx_interval.data)
    txin = random.choice(tx.inputs)

    from hathor.transaction.scripts import P2PKH, parse_address_script
    spent_tx = tx.get_spent_tx(txin)
    spent_txout = spent_tx.outputs[txin.index]
    p2pkh = parse_address_script(spent_txout.script)
    assert isinstance(p2pkh, P2PKH)

    from hathor.wallet.base_wallet import WalletInputInfo, WalletOutputInfo
    value = spent_txout.value
    private_key = manager.wallet.get_private_key(p2pkh.address)
    inputs = [WalletInputInfo(tx_id=txin.tx_id, index=txin.index, private_key=private_key)]

    address = manager.wallet.get_unused_address(mark_as_used=True)
    outputs = [WalletOutputInfo(address=decode_address(address), value=int(value), timelock=None)]

    tx2 = manager.wallet.prepare_transaction(Transaction, inputs, outputs, manager.tx_storage)
    tx2.storage = manager.tx_storage
    tx2.weight = 1
    tx2.timestamp = max(tx.timestamp + 1, int(manager.reactor.seconds()))

    if use_same_parents:
        tx2.parents = list(tx.parents)
    else:
        tx2.parents = manager.get_new_tx_parents(tx2.timestamp)

    tx2.resolve()
    return tx2
    def decode_put_params(self, data: Dict[str, Any]) -> DecodedPutParams:
        """Decode the data required on PUT request. Raise an error if any of the
        fields is not of the expected type.
        """
        value_dict = {}
        try:
            for item in data['new_values']:
                addr = decode_address(item['address'])
                value_dict[addr] = int(item['value'])
        except InvalidAddress:
            raise ValueError('Invalid \'address\' in parameters: {}'.format(item['address']))
        except ValueError:
            raise ValueError('Invalid \'value\' in parameters: {}'.format(item['value']))

        try:
            input_value = int(data['input_value'])
        except ValueError:
            raise ValueError('Invalid \'input_value\' in parameters')

        try:
            tx_bytes = bytes.fromhex(data['hex_tx'])
        except ValueError:
            raise ValueError('Could not decode hex transaction')

        return DecodedPutParams(value_dict, input_value, tx_bytes)
    def setUp(self):
        super().setUp()

        self.network = 'testnet'
        self.manager = self.create_peer(self.network, unlock_wallet=True)

        blocks = add_new_blocks(self.manager, 3, advance_clock=15)
        self.blocks_tokens = [
            sum(txout.value for txout in blk.outputs) for blk in blocks
        ]

        address = self.get_address(0)
        value = 100

        self.initial_balance = sum(self.blocks_tokens[:3]) - 100

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value),
                             timelock=None)
        ]

        add_blocks_unlock_reward(self.manager)

        self.tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs)
        self.tx1.weight = 10
        self.tx1.parents = self.manager.get_new_tx_parents()
        self.tx1.timestamp = int(self.clock.seconds())
        self.tx1.resolve()
        self.manager.propagate_tx(self.tx1)
        self.run_to_completion()
    def setUp(self):
        super().setUp()

        self.network = 'testnet'
        self.manager = self.create_peer(self.network,
                                        unlock_wallet=True,
                                        wallet_index=True)

        # Unlocking wallet
        self.manager.wallet.unlock(b'MYPASS')

        add_new_blocks(self.manager, 1, advance_clock=1)
        add_blocks_unlock_reward(self.manager)
        tx = create_tokens(self.manager,
                           mint_amount=100,
                           token_name='Teste',
                           token_symbol='TST')
        self.token_uid = tx.tokens[0]

        # Create a tx with the same address, so we can have more tx in the history
        output = tx.outputs[0]
        script_type_out = parse_address_script(output.script)
        self.address = script_type_out.address

        # Using token creation address as search address
        # Token creation address has change output for the genesis (1B - 0.01 HTR of token deposit)
        self.address_bytes = decode_address(self.address)
        add_new_blocks(self.manager,
                       5,
                       advance_clock=1,
                       address=self.address_bytes)
Beispiel #14
0
    def render_GET(self, request):
        """ GET request for /get_block_template/
        """
        request.setHeader(b'content-type', b'application/json; charset=utf-8')
        set_cors(request, 'GET')

        # params
        raw_address = request.args.get(b'address')
        if raw_address:
            address = decode_address(raw_address[0].decode())
        else:
            address = b''
        caps = set(map(lambda s: Capabilities(s.decode()), request.args.get(b'capabilities', [])))
        merged_mining = Capabilities.MERGED_MINING in caps

        if not self.manager.can_start_mining():
            self.log.debug('cannot generate Block Template, node syncing')
            # XXX: HTTP 503 Service Unavailable is suitable for temporary server errors
            raise APIError('Node syncing', 503)

        # get block
        # XXX: miner can edit block data and output_script, so it's fine if address is None
        block = self.manager.generate_mining_block(address=address, merge_mined=merged_mining)

        # serialize
        data = block.to_json(include_metadata=True)
        data.pop('hash')
        data.pop('inputs')
        data.pop('nonce', None)
        data.pop('aux_pow', None)

        return json_dumpb(data)
Beispiel #15
0
    def test_maybe_spent_txs(self):
        add_new_block(self.manager, advance_clock=15)
        blocks = add_blocks_unlock_reward(self.manager)
        w = self.manager.wallet
        new_address = w.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), 1, timelock=None)
        tx1 = w.prepare_transaction_compute_inputs(Transaction, outputs=[out])
        self.assertEqual(len(tx1.inputs), 1)
        _input = tx1.inputs[0]
        key = (_input.tx_id, _input.index)
        self.assertNotIn(key, w.unspent_txs[settings.HATHOR_TOKEN_UID])
        self.assertIn(key, w.maybe_spent_txs[settings.HATHOR_TOKEN_UID])
        self.run_to_completion()
        self.assertIn(key, w.unspent_txs[settings.HATHOR_TOKEN_UID])
        self.assertEqual(0, len(w.maybe_spent_txs[settings.HATHOR_TOKEN_UID]))

        # when we receive the new tx it will remove from maybe_spent
        tx2 = w.prepare_transaction_compute_inputs(Transaction, outputs=[out])
        tx2.storage = self.manager.tx_storage
        tx2.timestamp = max(
            tx2.get_spent_tx(txin).timestamp for txin in tx2.inputs) + 1
        tx2.parents = self.manager.get_new_tx_parents(tx2.timestamp)
        tx2.weight = 1
        tx2.timestamp = blocks[-1].timestamp + 1
        tx2.resolve()
        self.assertTrue(self.manager.on_new_tx(tx2, fails_silently=False))
        self.clock.advance(2)
        self.assertEqual(0, len(w.maybe_spent_txs[settings.HATHOR_TOKEN_UID]))
Beispiel #16
0
    def test_invalid_address(self):
        w = Wallet(directory=self.directory)
        w.unlock(PASSWORD)

        # creating valid address
        valid_address = '15d14K5jMqsN2uwUEFqiPG5SoD7Vr1BfnH'
        WalletOutputInfo(decode_address(valid_address), 100, None)

        # creating invalid address
        invalid_address = '5d14K5jMqsN2uwUEFqiPG5SoD7Vr1BfnH'
        with self.assertRaises(InvalidAddress):
            WalletOutputInfo(decode_address(invalid_address), 100, None)

        # invalid address (checksum invalid)
        invalid_address2 = '15d14K5jMqsN2uwUEFqiPG5SoD7Vr1Bfnq'
        with self.assertRaises(InvalidAddress):
            WalletOutputInfo(decode_address(invalid_address2), 100, None)
Beispiel #17
0
    def test_twin_tx(self):
        add_new_blocks(self.manager, 5, advance_clock=15)
        add_blocks_unlock_reward(self.manager)

        address = self.get_address(0)
        value1 = 100
        value2 = 101

        outputs = [
            WalletOutputInfo(address=decode_address(address),
                             value=int(value1),
                             timelock=None),
            WalletOutputInfo(address=decode_address(address),
                             value=int(value2),
                             timelock=None)
        ]

        tx1 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, outputs, self.manager.tx_storage)
        tx1.weight = 10
        tx1.parents = self.manager.get_new_tx_parents()
        tx1.timestamp = int(self.clock.seconds())
        tx1.resolve()

        # Change of parents only, so it's a twin
        tx2 = Transaction.create_from_struct(tx1.get_struct())
        tx2.parents = [tx1.parents[1], tx1.parents[0]]
        tx2.resolve()
        self.assertNotEqual(tx1.hash, tx2.hash)

        self.manager.propagate_tx(tx1)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 1)
        self.assertEqual(wallet_data, [tx1.hash])

        # Propagate a conflicting twin transaction
        self.manager.propagate_tx(tx2)
        self.run_to_completion()

        wallet_data = self.manager.tx_storage.wallet_index.get_from_address(
            address)
        self.assertEqual(len(wallet_data), 2)
        self.assertEqual(set(wallet_data), set([tx1.hash, tx2.hash]))
Beispiel #18
0
    def test_insuficient_funds(self):
        w = Wallet(directory=self.directory)
        w.unlock(PASSWORD)

        # create transaction spending some value
        new_address = w.get_unused_address()
        out = WalletOutputInfo(decode_address(new_address), 100, timelock=None)
        with self.assertRaises(InsufficientFunds):
            w.prepare_transaction_compute_inputs(Transaction, outputs=[out])
Beispiel #19
0
 def test_prepare_transaction(self):
     block = add_new_block(self.manager, advance_clock=5)
     w = self.manager.wallet
     new_address = w.get_unused_address()
     out = WalletOutputInfo(decode_address(new_address), 1, timelock=None)
     with self.assertRaises(InsufficientFunds):
         w.prepare_transaction_compute_inputs(Transaction,
                                              outputs=[out],
                                              timestamp=block.timestamp)
Beispiel #20
0
    def setUp(self):
        super().setUp()

        self.network = 'testnet'
        self.manager = self.create_peer(self.network, unlock_wallet=True)

        self.public_keys = [
            bytes.fromhex(
                '0250bf5890c9c6e9b4ab7f70375d31b827d45d0b7b4e3ba1918bcbe71b412c11d7'
            ),
            bytes.fromhex(
                '02d83dd1e9e0ac7976704eedab43fe0b79309166a47d70ec3ce8bbb08b8414db46'
            ),
            bytes.fromhex(
                '02358c539fa7474bf12f774749d0e1b5a9bc6e50920464818ebdb0043b143ae2ba'
            )
        ]

        self.private_keys = [
            '3081de304906092a864886f70d01050d303c301b06092a864886f70d01050c300e04089abeae5e8a8f75d302020800301d060960'
            '864801650304012a0410abbde27221fd302280c13fca7887c85e048190c41403f39b1e9bbc5b6b7c3be4729c054fae9506dc0f83'
            '61adcff0ea393f0bb3ca9f992fc2eea83d532691bc9a570ed7fb9e939e6d1787881af40b19fb467f06595229e29b5a6268d831f0'
            '287530c7935d154deac61dd4ced988166f9c98054912935b607e2fb332e11c95b30ea4686eb0bda7dd57ed1eeb25b07cea9669dd'
            'e5210528a00653159626a5baa61cdee7f4',
            '3081de304906092a864886f70d01050d303c301b06092a864886f70d01050c300e040817ca6c6c47ade0de02020800301d060960'
            '864801650304012a041003746599b1d7dde5b875e4d8e2c4c157048190a25ccabb17e603260f8a1407bdca24904b6ae0aa9ae225'
            'd87552e5a9aa62d98b35b2c6c78f33cb051f3a3932387b4cea6f49e94f14ee856d0b630d77c1299ad7207b0be727d338cf92a3ff'
            'fe232aff59764240aff84e079a5f6fb3355048ac15703290a005a9a033fdcb7fcf582a5ddf6fd7b7c1193bd7912cd275a88a8a68'
            '23b6c3ed291b4a3f4724875a3ae058054c',
            '3081de304906092a864886f70d01050d303c301b06092a864886f70d01050c300e0408089f48fbf59fa92902020800301d060960'
            '864801650304012a041072f553e860b77654fd5fb80e5891e7c90481900fde272b88f9a70e7220b2d5adeda1ed29667527caedc2'
            '385be7f9e0d63defdde20557e90726e102f879eaf2233cceca8d4af239d5b2a159467255446f001c99b69e570bb176b95248fc21'
            'cb752d463b494c2195411639989086336a530d1f4eae91493faf89368f439991baa947ebeca00be7f5099ed69606dc78a4cc384d'
            '41542350a9054c5fa1295305dfc37e5989'
        ]

        self.redeem_script = generate_multisig_redeem_script(
            2, self.public_keys)

        self.multisig_address_b58 = generate_multisig_address(
            self.redeem_script)
        self.multisig_address = decode_address(self.multisig_address_b58)
        self.address = decode_address(self.manager.wallet.get_unused_address())
        self.outside_address = decode_address(self.get_address(0))
Beispiel #21
0
    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)
Beispiel #22
0
 def test_insuficient_funds(self):
     add_blocks_unlock_reward(self.manager)
     # create transaction spending some value
     new_address = self.wallet.get_unused_address()
     out = WalletOutputInfo(decode_address(new_address),
                            self.TOKENS,
                            timelock=None)
     with self.assertRaises(InsufficientFunds):
         self.wallet.prepare_transaction_compute_inputs(
             Transaction, [out], self.tx_storage)
Beispiel #23
0
def execute(args: Namespace) -> None:
    from hathor.crypto.util import decode_address
    from hathor.stratum import StratumClient
    from hathor.wallet.exceptions import InvalidAddress

    address = None
    if args.address is not None:
        try:
            decode_address(args.address)
            address = args.address
        except InvalidAddress:
            print('The given address is invalid')
            sys.exit(-1)

    miner = StratumClient(proc_count=args.nproc, address=address)
    miner.start()
    point = TCP4ClientEndpoint(reactor, args.host, args.port)
    connectProtocol(point, miner)
    reactor.run()
    def decode_post_params(self, data: Dict[str, Any]) -> DecodedPostParams:
        """Decode the data required on POST request. Raise an error if any of the
        fields is not of the expected type.
        """
        value_dict = {}
        try:
            for item in data['values']:
                addr = decode_address(item['address'])
                value_dict[addr] = int(item['value'])
        except InvalidAddress:
            raise ValueError('Invalid \'address\' in parameters: {}'.format(item['address']))
        except ValueError:
            raise ValueError('Invalid \'value\' in parameters: {}'.format(item['value']))

        if data['fallback_address']:
            try:
                fallback_address = decode_address(data['fallback_address'])
            except InvalidAddress:
                raise ValueError('Invalid \'fallback_address\' in parameters')
        else:
            fallback_address = b'\x00'

        if data.get('min_timestamp'):
            try:
                min_timestamp = int(data['min_timestamp'])
            except ValueError:
                raise ValueError('Invalid \'min_timestamp\' in parameters')
        else:
            min_timestamp = int(self.manager.reactor.seconds())

        try:
            oracle_pubkey_hash = base64.b64decode(data['oracle_pubkey_hash'])
        except binascii.Error:
            raise ValueError('Invalid \'oracle_pubkey_hash\' in parameters')

        try:
            total_value = int(data['total_value'])
        except ValueError:
            raise ValueError('Invalid \'total_value\' in parameters')

        return DecodedPostParams(value_dict, fallback_address, min_timestamp, oracle_pubkey_hash, total_value,
                                 data['oracle_data_id'].encode('utf-8'), data['input_value'])
Beispiel #25
0
def create_base_script(address: str,
                       timelock: Optional[Any] = None) -> BaseScript:
    """ Verifies if address is P2PKH or Multisig and return the corresponding BaseScript implementation.
    """
    baddress = decode_address(address)
    if baddress[0] == binary_to_int(settings.P2PKH_VERSION_BYTE):
        return P2PKH(address, timelock)
    elif baddress[0] == binary_to_int(settings.MULTISIG_VERSION_BYTE):
        return MultiSig(address, timelock)
    else:
        raise ScriptError('The address is not valid')
Beispiel #26
0
 def test_block_increase_balance(self):
     # generate a new block and check if we increase balance
     w = Wallet(directory=self.directory)
     w.unlock(PASSWORD)
     new_address = w.get_unused_address()
     key = w.keys[new_address]
     out = WalletOutputInfo(decode_address(key.address),
                            BLOCK_REWARD,
                            timelock=None)
     tx = w.prepare_transaction(Transaction, inputs=[], outputs=[out])
     tx.update_hash()
     w.on_new_tx(tx)
     utxo = w.unspent_txs[settings.HATHOR_TOKEN_UID].get((tx.hash, 0))
     self.assertIsNotNone(utxo)
     self.assertEqual(w.balance[settings.HATHOR_TOKEN_UID],
                      WalletBalance(0, BLOCK_REWARD))
Beispiel #27
0
def from_raw_output(raw_output: Dict, tokens: List[bytes]) -> TxOutput:
    value = raw_output['value']
    token_uid = raw_output.get('token_uid')
    if token_uid is not None:
        if token_uid not in tokens:
            tokens.append(token_uid)
        token_data = tokens.index(token_uid) + 1
    else:
        token_data = 0
    raw_script = raw_output.get('script')
    if raw_script:
        script = base64.b64decode(raw_script)
    else:
        address = decode_address(raw_output['address'])
        script = create_output_script(address)
    return TxOutput(value, script, token_data)
    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)
Beispiel #29
0
    def handle_subscribe(self, params: Dict, msgid: Optional[str]) -> None:
        """ Handles subscribe request by answering it and triggering a job request.

        :param msgid: JSON-RPC 2.0 message id
        :type msgid: Optional[str]
        """
        assert self.miner_id is not None
        if params and 'address' in params and params['address'] is not None:
            try:
                self.miner_address = decode_address(params['address'])
            except InvalidAddress:
                self.send_error(INVALID_ADDRESS, msgid)
                self.transport.loseConnection()
                return

        self.log.info('Miner subscribed', address=self.miner_address)
        self.send_result([str(self.miner_id), self.xnonce1.hex(), self.xnonce2_size], msgid)
Beispiel #30
0
    def test_create_token_transaction(self):
        add_new_block(self.manager, advance_clock=5)
        add_blocks_unlock_reward(self.manager)
        tx = create_tokens(self.manager)

        tokens_created = tx.outputs[0].value
        token_uid = tx.tokens[0]
        address_b58 = self.manager.wallet.get_unused_address()
        address = decode_address(address_b58)

        _, hathor_balance = self.manager.wallet.balance[
            settings.HATHOR_TOKEN_UID]
        # prepare tx with hathors and another token
        # hathor tx
        hathor_out = WalletOutputInfo(address, hathor_balance, None)
        # token tx
        token_out = WalletOutputInfo(address, tokens_created - 20, None,
                                     token_uid.hex())

        tx2 = self.manager.wallet.prepare_transaction_compute_inputs(
            Transaction, [hathor_out, token_out])
        tx2.storage = self.manager.tx_storage
        tx2.timestamp = tx.timestamp + 1
        tx2.parents = self.manager.get_new_tx_parents()
        tx2.resolve()
        tx2.verify()

        self.assertNotEqual(len(tx2.inputs), 0)
        token_dict = defaultdict(int)
        for _input in tx2.inputs:
            output_tx = self.manager.tx_storage.get_transaction(_input.tx_id)
            output = output_tx.outputs[_input.index]
            token_uid = output_tx.get_token_uid(output.get_token_index())
            token_dict[token_uid] += output.value

        # make sure balance is the same and we've checked both balances
        did_enter = 0
        for token_uid, value in token_dict.items():
            if token_uid == settings.HATHOR_TOKEN_UID:
                self.assertEqual(value, hathor_balance)
                did_enter += 1
            elif token_uid == token_uid:
                self.assertEqual(value, tokens_created)
                did_enter += 1

        self.assertEqual(did_enter, 2)