def create_wallet(self):
        if self.created:
            return fail(RuntimeError(f"{self.network} wallet with name {self.wallet_name} already exists."))

        self._logger.info("Creating wallet in %s", self.wallet_dir)
        try:
            self.wallet = HDWallet.create(self.wallet_name, network=self.network, db_uri=self.db_path)
            self.wallet.new_key('tribler_payments')
            self.wallet.new_key('tribler_change', change=1)
            self.created = True
        except WalletError as exc:
            self._logger.error("Cannot create %s wallet!", self.network)
            return fail(exc)
        return succeed(None)
Beispiel #2
0
    async def transfer(self, amount: float, address, **kwargs) -> Future:
        """
        Transfer Monero to another wallet.
        If the amount exceeds the available balance, an `InsufficientFunds` exception is raised.

        :param kwargs:
            payment_id: str,
            priority: transaction priority, implies fee.
                The priority can be a number from 1 to 4 (unimportant, normal, elevated, priority).
                Default is 1.
            unlock_time: int, default is 0
        :param amount: the transfer amount
        :param address: the receiver address
        :return: Future of transfer hash, None or InsufficientFundsException
        """
        if self._wallet_connection_alive():
            balance = await self.get_balance()

            if balance['available'] < amount:
                return fail(InsufficientFunds('Insufficient funds found in Monero wallet'))

            self._logger.info('Transfer %f to %s', amount, address)
            transaction = await self.wallet.transfer(address, Decimal(str(amount)), **kwargs, relay=False)
            return succeed(transaction.hash)
        return succeed(None)
Beispiel #3
0
    def merge_account(self, address):
        """
        Delete the wallet and send all funds to the specified address
        :param address: address to send funds to
        :return: tx hash
        """
        self.check_and_update_created_on_network()
        if not self.created_on_network:
            return fail(
                RuntimeError(
                    'Cannot do account merge operation: account is not created on network'
                ))
        self._logger.info(
            'Deleting wallet and sending all funds to address %s', address)
        network = Network.PUBLIC_NETWORK_PASSPHRASE if not self.testnet else Network.TESTNET_NETWORK_PASSPHRASE
        tx = TransactionBuilder(
            source_account=self.account,
            base_fee=self.provider.get_base_fee(),
            network_passphrase=network,
        ).append_account_merge_op(address).build()

        tx.sign(self.keypair)
        xdr_tx_envelope = tx.to_xdr()

        tx_hash = self.provider.submit_transaction(xdr_tx_envelope)
        self.created_on_network = False
        return succeed(tx_hash)
 async def test_transfer_error(self):
     """
     Test whether we receive the right response when we try a transfer that errors
     """
     self.market_community.wallets['BTC'].transfer = lambda *_: fail(RuntimeError("error"))
     self.market_community.wallets['BTC'].created = True
     post_data = {'amount': 3, 'destination': 'abc'}
     await self.make_request(self.nodes[0], 'wallets/BTC/transfer', 'POST', expected_status=500, json=post_data)
Beispiel #5
0
 async def test_transfer_error(self):
     """
     Test whether we receive the right response when we try a transfer that errors
     """
     self.nodes[0].overlay.wallets['BTC'].transfer = lambda *_: fail(RuntimeError("error"))
     self.nodes[0].overlay.wallets['BTC'].created = True
     self.should_check_equality = False
     post_data = {'amount': 3, 'destination': 'abc'}
     await self.do_request('wallets/BTC/transfer', expected_code=500, request_type='POST', post_data=post_data)
Beispiel #6
0
    def get_outgoing_payments(self, confirmed=True):
        """
        Get all confirmed outgoing payments for this wallet.

        :param: if True return only confirmed outgoing payments, else mempool payments
        :return: list of payments
        """
        if self._wallet_connection_alive():
            return succeed(self.wallet.outgoing(confirmed=confirmed, unconfirmed=(not confirmed)))
        return fail(WalletConnectionError())
Beispiel #7
0
    def get_confirmations(self, transaction: Payment):
        """
        Return number of confirmations transactions has received.

        :param transaction: Payment object from monero-python library
        :return: integer count
        """
        if self._wallet_connection_alive():
            return succeed(self.wallet.confirmations(transaction))
        return fail(WalletConnectionError())
Beispiel #8
0
 def insert_bid(self, bid):
     """
     :type bid: Bid
     """
     if not self._bids.tick_exists(bid.order_id) and bid.order_id not in self.completed_orders and bid.is_valid():
         self._bids.insert_tick(bid)
         delay = int(bid.timestamp) + int(bid.timeout) * 1000 - int(time.time() * 1000)
         return self.register_task("bid_%s_timeout" % bid.order_id, self.timeout_bid, bid.order_id, delay=delay)
     self.on_invalid_tick_insert()
     return fail(RuntimeError("bid invalid"))
Beispiel #9
0
 def insert_ask(self, ask):
     """
     :type ask: Ask
     """
     if not self._asks.tick_exists(ask.order_id) and ask.order_id not in self.completed_orders and ask.is_valid():
         self._asks.insert_tick(ask)
         delay = int(ask.timestamp) + int(ask.timeout) * 1000 - int(time.time() * 1000)
         return self.register_task("ask_%s_timeout" % ask.order_id, self.timeout_ask, ask.order_id, delay=delay)
     self.on_invalid_tick_insert()
     return fail(RuntimeError("ask invalid"))
Beispiel #10
0
    async def get_transactions(self):
        """
        Retrieve all transactions associated with this Monero wallet.

        :return: list of dictionary representations of transactions
        """
        if self._wallet_connection_alive():
            payments = await self._get_payments()
            transactions = [self._normalize_transaction(payment) for payment in payments]
            return succeed(transactions)
        return fail(WalletConnectionError('No connection to wallet for retrieving transactions'))
Beispiel #11
0
    async def transfer_multiple(self, transfers: list, **kwargs) -> list:
        """
        Submit multiple transfers simultaneously to the Monero blockchain.
        May reduce fee.

        :param transfers: list of tuples of format (address, Decimal(amount))
        :param kwargs: payment_id, priority, unlock_time (see `transfer` method above)
        :return: list of resulting hashes or return InsufficientFundsException
        """
        balance = await self.get_balance()

        total_amount = float(sum([transfer[1] for transfer in transfers]))

        if balance['available'] < total_amount:
            return fail(InsufficientFunds('Insufficient funds found in Monero wallet for all transfers'))

        if self._wallet_connection_alive():
            results = await self.wallet.transfer_multiple(transfers, **kwargs)
            hashes = [result[0].hash for result in results]
            return succeed(hashes)
        return fail(WalletConnectionError('No connection to wallet for making transfers'))
Beispiel #12
0
 def create_wallet(self):
     """
     Anydex operates on existing wallet with corresponding `wallet-rpc-server`.
     Creates instance of `monero-python` Wallet instance.
     """
     self._logger.info('Connect to wallet-rpc-server on %s at %d', self.host, self.port)
     try:
         self.wallet = monero.wallet.Wallet(JSONRPCWallet(host=self.host, port=self.port))
         self.created = True
         self._logger.info('Connection to wallet-rpc-server established')
         return succeed(None)
     except requests.exceptions.ConnectionError:
         return fail(WalletConnectionError(f'Cannot connect to wallet-rpc-server on {self.host} at {self.port}'))
Beispiel #13
0
    def create_wallet(self):
        """
        Create a new bitcoin wallet.
        """
        from bitcoinlib.wallets import wallet_exists, HDWallet, WalletError

        if wallet_exists(self.wallet_name, databasefile=self.db_path):
            return fail(
                RuntimeError(
                    f"Bitcoin wallet with name {self.wallet_name} already exists."
                ))

        self._logger.info("Creating wallet in %s", self.wallet_dir)
        try:
            self.wallet = HDWallet.create(self.wallet_name,
                                          network=self.network,
                                          databasefile=self.db_path)
            self.wallet.new_key('tribler_payments')
            self.wallet.new_key('tribler_change', change=1)
            self.created = True
        except WalletError as exc:
            self._logger.error("Cannot create BTC wallet!")
            return fail(exc)
        return succeed(None)
Beispiel #14
0
    def create_wallet(self):
        if self.created:
            return fail(
                RuntimeError(
                    f'Stellar wallet with name {self.wallet_name} already exists'
                ))

        self._logger.info('Creating Stellar wallet with name %s',
                          self.wallet_name)
        self.keypair = Keypair.random()
        self.created = True
        self.account = Account(self.get_address().result(), 0)
        self.created_on_network = False
        self.database.add_secret(self.wallet_name, self.keypair.secret,
                                 self.keypair.public_key)

        return succeed(None)
Beispiel #15
0
    def create_wallet(self):
        """
        Create wallet by creating seed, storing it and setting up API access
        """
        if self.created:
            return fail(RuntimeError(f'Iota wallet with name {self.wallet_name} already exists.'))

        self._logger.info(f'Creating Iota wallet with name {self.wallet_name}')

        # generate random seed and store it in the database as a String instead of TryteString
        self.seed = Seed.random()
        self.database.add(DatabaseSeed(name=self.wallet_name, seed=self.seed.__str__()))
        self.database.commit()

        # initialize connection with API through the provider and get an active non-spent address
        self.provider = PyOTAIotaProvider(testnet=self.testnet, seed=self.seed)
        self.created = True
        return succeed([])
Beispiel #16
0
    def create_wallet(self):
        """
        If no account exists yet, create a new one.
        """
        if self.account:
            return fail(
                RuntimeError(
                    f'Ethereum wallet with name {self.wallet_name} already exists'
                ))

        self._logger.info('Creating Ethereum wallet with name %s',
                          self.wallet_name)
        if not self.account:
            self.account = Web3().eth.account.create()
            self.created = True
            self.database.add_key(self.wallet_name, self.account.key,
                                  self.account.address)

        return succeed(None)
Beispiel #17
0
async def test_change_hops_fail(mock_dlmgr, test_download, rest_api):
    """
    Testing whether the API returns 500 if changing the number of hops in a download fails
    """
    mock_dlmgr.get_download = lambda _: test_download
    mock_dlmgr.update_hops = lambda *_: fail(RuntimeError)

    await do_request(rest_api,
                     f'downloads/{test_download.infohash}',
                     post_data={'anon_hops': 1},
                     expected_code=500,
                     request_type='PATCH',
                     expected_json={
                         'error': {
                             'message': '',
                             'code': 'RuntimeError',
                             'handled': True
                         }
                     })
Beispiel #18
0
def create_node(network: str, testnet=False) -> Node:
    """
    Constructs a Node from user-provided parameters if key is present in `config.py`-dictionary.
    Else: constructs Node picked from set of default nodes provided by AnyDex.

    Return CannotCreateNodeException if required parameters miss from user Node-config: host, port

    :param testnet: testnet node or not
    :param network: instance of Cryptocurrency enum
    :return: Node
    """
    config = get_anydex_configuration()
    params = {'network': network}

    if 'node' in config:
        _logger.info('Parsing user node config')

        node_config = config['node_config']
        params['source'] = Source.USER
        params['name'] = node_config.get('name', '')

        try:
            protocol, username, password, host, port = _parse_url(
                node_config['host'])
        except KeyError:
            return fail(
                CannotCreateNodeException(
                    'Missing key `host` from node config'))

        if port is None:
            return fail(
                CannotCreateNodeException(
                    'Missing port from `host` in node config'))

        params['protocol'] = protocol if protocol else 'http'
        params['username'] = username if username else ''
        params['password'] = password if username else ''

        _, params['latency'] = determine_latency(node_config['host'])

        params['host_config'] = HostConfig(host, port, params['protocol'])
    else:
        _logger.info('Finding best host from pool of default hosts')

        params['source'] = Source.DEFAULT
        params['name'] = ''

        default_hosts = read_default_hosts()

        try:
            if testnet:
                network_hosts = default_hosts[network]['testnet']
                params['testnet'] = True
            else:
                network_hosts = default_hosts[network]['non_testnet']
        except KeyError:
            return fail(
                CannotCreateNodeException(
                    f'Missing default nodes for {network}'))

        # host format: protocol://username:password@domain:port
        selected_host, latency = select_best_host(network_hosts)
        protocol, username, password, host, port = _parse_url(selected_host)

        if username:
            params['username'] = username
        if password:
            params['password'] = password

        if protocol:
            params['host_config'] = HostConfig(host, port, protocol)
        else:
            params['host_config'] = HostConfig(host, port)

        params['latency'] = latency

    node = Node(**params)
    _logger.info('Using following node:\n%s', node)
    return node
Beispiel #19
0
    def sign_block(self,
                   peer,
                   public_key=EMPTY_PK,
                   block_type=b'unknown',
                   transaction=None,
                   linked=None,
                   additional_info=None):
        """
        Create, sign, persist and send a block signed message
        :param peer: The peer with whom you have interacted, as a IPv8 peer
        :param public_key: The public key of the other party you transact with
        :param block_type: The type of the block to be constructed, as a string
        :param transaction: A string describing the interaction in this block
        :param linked: The block that the requester is asking us to sign
        :param additional_info: Stores additional information, on the transaction
        """
        # NOTE to the future: This method reads from the database, increments and then writes back. If in some future
        # this method is allowed to execute in parallel, be sure to lock from before .create up to after .add_block

        # In this particular case there must be an implicit transaction due to the following assert
        assert peer is not None or peer is None and linked is None and public_key == ANY_COUNTERPARTY_PK, \
            "Peer, linked block should not be provided when creating a no counterparty source block. Public key " \
            "should be that reserved for any counterpary."
        assert transaction is None and linked is not None or transaction is not None and linked is None, \
            "Either provide a linked block or a transaction, not both %s, %s" % (peer, self.my_peer)
        assert (additional_info is None or additional_info is not None and linked is not None
                and transaction is None), \
            "Either no additional info is provided or one provides it for a linked block"
        assert (linked is None or linked.link_public_key
                == self.my_peer.public_key.key_to_bin()
                or linked.link_public_key == ANY_COUNTERPARTY_PK
                ), "Cannot counter sign block not addressed to self"
        assert linked is None or linked.link_sequence_number == UNKNOWN_SEQ, \
            "Cannot counter sign block that is not a request"
        assert transaction is None or isinstance(
            transaction, dict), "Transaction should be a dictionary"
        assert additional_info is None or isinstance(
            additional_info, dict), "Additional info should be a dictionary"

        self.persistence_integrity_check()

        if linked and linked.link_public_key != ANY_COUNTERPARTY_PK:
            block_type = linked.type

        block = self.get_block_class(block_type).create(
            block_type,
            transaction,
            self.persistence,
            self.my_peer.public_key.key_to_bin(),
            link=linked,
            additional_info=additional_info,
            link_pk=public_key)
        block.sign(self.my_peer.key)

        validation = block.validate(self.persistence)
        self.logger.info("Signed block to %s (%s) validation result %s",
                         hexlify(block.link_public_key)[-8:], block,
                         validation)
        if validation[0] != ValidationResult.partial_next and validation[
                0] != ValidationResult.valid:
            self.logger.error("Signed block did not validate?! Result %s",
                              repr(validation))
            return fail(RuntimeError("Signed block did not validate."))

        if not self.persistence.contains(block):
            self.persistence.add_block(block)
            self.notify_listeners(block)

        # This is a source block with no counterparty
        if not peer and public_key == ANY_COUNTERPARTY_PK:
            if block.type not in self.settings.block_types_bc_disabled:
                self.send_block(block)
            return succeed((block, None))

        # If there is a counterparty to sign, we send it
        self.send_block(block, address=peer.address)

        # We broadcast the block in the network if we initiated a transaction
        if block.type not in self.settings.block_types_bc_disabled and not linked:
            self.send_block(block)

        if peer == self.my_peer:
            # We created a self-signed block
            if block.type not in self.settings.block_types_bc_disabled:
                self.send_block(block)

            return succeed(
                (block,
                 None)) if public_key == ANY_COUNTERPARTY_PK else succeed(
                     (block, linked))
        elif not linked:
            # We keep track of this outstanding sign request.
            sign_future = Future()
            self.request_cache.add(
                HalfBlockSignCache(self, block, sign_future, peer.address))
            return sign_future
        else:
            # We return a future that fires immediately with both half blocks.
            if block.type not in self.settings.block_types_bc_disabled:
                self.send_block_pair(linked, block)

            return succeed((linked, block))