示例#1
0
 def reserve_funds_or_cancel(self, client_blob_request):
     reserved_points = self._reserve_points(client_blob_request.max_pay_units)
     if reserved_points is not None:
         return reserved_points
     client_blob_request.cancel(InsufficientFundsError())
     client_blob_request.finished_deferred.addErrback(lambda _: True)
     raise InsufficientFundsError()
示例#2
0
    def send_next_request(self, peer, protocol):
        sent_request = False
        if self._blobs_to_download() and self._should_send_request_to(peer):
            a_r = self._get_availability_request(peer)
            d_r = self._get_download_request(peer)
            p_r = None

            if a_r is not None or d_r is not None:
                p_r = self._get_price_request(peer, protocol)

            if a_r is not None:
                d1 = protocol.add_request(a_r)
                d1.addCallback(self._handle_availability, peer, a_r)
                d1.addErrback(self._request_failed, "availability request",
                              peer)
                sent_request = True
            if d_r is not None:
                reserved_points = self._reserve_points(peer, protocol,
                                                       d_r.max_pay_units)
                if reserved_points is not None:
                    # Note: The following three callbacks will be called when the blob has been
                    # fully downloaded or canceled
                    d_r.finished_deferred.addCallbacks(
                        self._download_succeeded,
                        self._download_failed,
                        callbackArgs=(peer, d_r.blob),
                        errbackArgs=(peer, ))
                    d_r.finished_deferred.addBoth(self._pay_or_cancel_payment,
                                                  protocol, reserved_points,
                                                  d_r.blob)
                    d_r.finished_deferred.addErrback(
                        self._handle_download_error, peer, d_r.blob)

                    d2 = protocol.add_blob_request(d_r)
                    # Note: The following two callbacks will be called as soon as the peer sends its
                    # response, which will be before the blob has finished downloading, but may be
                    # after the blob has been canceled. For example,
                    # 1) client sends request to Peer A
                    # 2) the blob is finished downloading from peer B, and therefore this one is canceled
                    # 3) client receives response from Peer A
                    # Therefore, these callbacks shouldn't rely on there being a blob about to be
                    # downloaded.
                    d2.addCallback(self._handle_incoming_blob, peer, d_r)
                    d2.addErrback(self._request_failed, "download request",
                                  peer)

                    sent_request = True
                else:
                    d_r.cancel(InsufficientFundsError())
                    d_r.finished_deferred.addErrback(lambda _: True)
                    return defer.fail(InsufficientFundsError())
            if sent_request is True:
                if p_r is not None:
                    d3 = protocol.add_request(p_r)
                    d3.addCallback(self._handle_price_response, peer, p_r,
                                   protocol)
                    d3.addErrback(self._request_failed, "price request", peer)
        return defer.succeed(sent_request)
示例#3
0
 def send_next_request(self, peer, protocol):
     # Basic idea:
     # If the peer has been sending us blob hashes to download recently (10 minutes?),
     # send back an example of one (the most recent?) so that it can
     # keep sending us more like it. Otherwise, just ask for
     # valuable blobs
     sent_request = False
     if self._should_send_request_to(peer):
         v_r = self._get_valuable_blob_request(peer)
         if v_r is not None:
             v_p_r = self._get_valuable_price_request(peer, protocol)
             reserved_points = self._reserve_points_valuable(
                 peer, protocol, v_r.max_pay_units)
             if reserved_points is not None:
                 d1 = protocol.add_request(v_r)
                 d1.addCallback(self._handle_valuable_blob_response, peer,
                                v_r)
                 d1.addBoth(self._pay_or_cancel_payment, protocol,
                            reserved_points, self._info_protocol_prices)
                 d1.addErrback(self._request_failed,
                               "valuable blob request", peer)
                 sent_request = True
                 if v_p_r is not None:
                     d2 = protocol.add_request(v_p_r)
                     d2.addCallback(self._handle_valuable_price_response,
                                    peer, v_p_r, protocol)
                     d2.addErrback(self._request_failed,
                                   "valuable price request", peer)
             else:
                 return defer.fail(InsufficientFundsError())
         i_r = self._get_info_request(peer)
         if i_r is not None:
             i_p_r = self._get_info_price_request(peer, protocol)
             reserved_points = self._reserve_points_info(
                 peer, protocol, i_r.max_pay_units)
             if reserved_points is not None:
                 d3 = protocol.add_request(i_r)
                 d3.addCallback(self._handle_info_response, peer, i_r,
                                protocol, reserved_points)
                 d3.addBoth(self._pay_or_cancel_payment, protocol,
                            reserved_points, self._valuable_protocol_prices)
                 d3.addErrback(self._request_failed, "info request", peer,
                               reserved_points)
                 sent_request = True
                 if i_p_r is not None:
                     d4 = protocol.add_request(i_p_r)
                     d4.addCallback(self._handle_info_price_response, peer,
                                    i_p_r, protocol)
                     d4.addErrback(self._request_failed,
                                   "info price request", peer)
             else:
                 return defer.fail(InsufficientFundsError())
     return defer.succeed(sent_request)
示例#4
0
    def claim_name(self, name, bid, metadata):
        """
        Claim a name, or update if name already claimed by user

        @param name: str, name to claim
        @param bid: float, bid amount
        @param metadata: Metadata compliant dict

        @return: Deferred which returns a dict containing below items
            txid - txid of the resulting transaction
            nout - nout of the resulting claim
            fee - transaction fee paid to make claim
            claim_id -  claim id of the claim
        """

        _metadata = Metadata(metadata)
        my_claim = yield self.get_my_claim(name)

        if my_claim:
            log.info("Updating claim")
            if self.get_balance() < Decimal(bid) - Decimal(my_claim['amount']):
                raise InsufficientFundsError()
            new_metadata = yield self.update_metadata(_metadata,
                                                      my_claim['value'])
            old_claim_outpoint = ClaimOutpoint(my_claim['txid'],
                                               my_claim['nout'])
            claim = yield self._send_name_claim_update(name,
                                                       my_claim['claim_id'],
                                                       old_claim_outpoint,
                                                       new_metadata, bid)
            claim['claim_id'] = my_claim['claim_id']
        else:
            log.info("Making a new claim")
            if self.get_balance() < bid:
                raise InsufficientFundsError()
            claim = yield self._send_name_claim(name, _metadata, bid)

        if not claim['success']:
            msg = 'Claim to name {} failed: {}'.format(name, claim['reason'])
            raise Exception(msg)

        claim = self._process_claim_out(claim)
        claim_outpoint = ClaimOutpoint(claim['txid'], claim['nout'])
        log.info("Saving metadata for claim %s %d", claim['txid'],
                 claim['nout'])

        yield self._save_name_metadata(name, claim_outpoint,
                                       _metadata['sources']['lbry_sd_hash'])
        defer.returnValue(claim)
示例#5
0
    def start(self, stream_info, name):
        def _cause_timeout(err):
            log.info('Cancelling download')
            self.timeout_counter = self.timeout * 2

        def _set_status(x, status):
            log.info("Download lbry://%s status changed to %s" %
                     (self.resolved_name, status))
            self.code = next(s for s in STREAM_STAGES if s[0] == status)
            return x

        def get_downloader_factory(metadata):
            for factory in metadata.factories:
                if isinstance(factory, ManagedEncryptedFileDownloaderFactory):
                    return factory, metadata
            raise Exception('No suitable factory was found in {}'.format(
                metadata.factories))

        def make_downloader(args):
            factory, metadata = args
            return factory.make_downloader(
                metadata, [self.data_rate, True],
                self.payment_rate_manager,
                download_directory=self.download_directory,
                file_name=self.file_name)

        self.resolved_name = name
        self.stream_info = deepcopy(stream_info)
        self.description = self.stream_info['description']
        self.stream_hash = self.stream_info['sources']['lbry_sd_hash']

        if 'fee' in self.stream_info:
            self.fee = FeeValidator(self.stream_info['fee'])
            max_key_fee = self._convert_max_fee()
            converted_fee = self.exchange_rate_manager.to_lbc(self.fee).amount
            if converted_fee > self.wallet.get_balance():
                log.warning("Insufficient funds to download lbry://%s",
                            self.resolved_name)
                return defer.fail(InsufficientFundsError())
            if converted_fee > max_key_fee:
                log.warning(
                    "Key fee %f above limit of %f didn't download lbry://%s",
                    converted_fee, max_key_fee, self.resolved_name)
                return defer.fail(KeyFeeAboveMaxAllowed())
            log.info("Key fee %f below limit of %f, downloading lbry://%s",
                     converted_fee, max_key_fee, self.resolved_name)

        self.checker.start(1)

        self.d.addCallback(lambda _: _set_status(None, DOWNLOAD_METADATA_CODE))
        self.d.addCallback(lambda _: download_sd_blob(
            self.session, self.stream_hash, self.payment_rate_manager))
        self.d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
        self.d.addCallback(lambda r: _set_status(r, DOWNLOAD_RUNNING_CODE))
        self.d.addCallback(get_downloader_factory)
        self.d.addCallback(make_downloader)
        self.d.addCallbacks(self._start_download, _cause_timeout)
        self.d.callback(None)

        return self.finished
示例#6
0
 def _pay_key_fee(self, address, fee_lbc, name):
     log.info("Pay key fee %f --> %s", fee_lbc, address)
     reserved_points = self.wallet.reserve_points(address, fee_lbc)
     if reserved_points is None:
         raise InsufficientFundsError(
             'Unable to pay the key fee of %s for %s' % (fee_lbc, name))
     return self.wallet.send_points_to_address(reserved_points, fee_lbc)
示例#7
0
    def claim_name(self, name, bid, metadata, certificate_id=None, claim_address=None,
                   change_address=None):
        """
        Claim a name, or update if name already claimed by user

        @param name: str, name to claim
        @param bid: float, bid amount
        @param metadata: ClaimDict compliant dict
        @param certificate_id: str (optional), claim id of channel certificate
        @param claim_address: str (optional), address to send claim to
        @param change_address: str (optional), address to send change

        @return: Deferred which returns a dict containing below items
            txid - txid of the resulting transaction
            nout - nout of the resulting claim
            fee - transaction fee paid to make claim
            claim_id -  claim id of the claim
        """

        decoded = ClaimDict.load_dict(metadata)
        serialized = decoded.serialized

        if self.get_balance() < Decimal(bid):
            raise InsufficientFundsError()

        claim = yield self._send_name_claim(name, serialized.encode('hex'),
                                            bid, certificate_id, claim_address, change_address)

        if not claim['success']:
            log.error(claim)
            msg = 'Claim to name {} failed: {}'.format(name, claim['reason'])
            raise Exception(msg)
        claim = self._process_claim_out(claim)
        yield self.storage.save_claim(self._get_temp_claim_info(claim, name, bid), smart_decode(claim['value']))
        defer.returnValue(claim)
示例#8
0
 def _pay_key_fee(self):
     if self.fee is not None:
         fee_lbc = self.exchange_rate_manager.to_lbc(self.fee).amount
         reserved_points = self.wallet.reserve_points(self.fee.address, fee_lbc)
         if reserved_points is None:
             return defer.fail(InsufficientFundsError())
         return self.wallet.send_points_to_address(reserved_points, fee_lbc)
     return defer.succeed(None)
示例#9
0
 def _pay_key_fee(self, address, fee_lbc, name):
     log.info("Pay key fee %s --> %s", dewies_to_lbc(fee_lbc), address)
     reserved_points = self.wallet.reserve_points(address, fee_lbc)
     if reserved_points is None:
         raise InsufficientFundsError(
             'Unable to pay the key fee of {} for {}'.format(
                 dewies_to_lbc(fee_lbc), name))
     return f2d(self.wallet.send_points_to_address(reserved_points,
                                                   fee_lbc))
示例#10
0
 def _claim_or_update(claim, metadata, _bid):
     if not claim:
         log.debug("No own claim yet, making a new one")
         if self.get_balance() < _bid:
             raise InsufficientFundsError()
         return self._send_name_claim(name, metadata, _bid)
     else:
         log.debug("Updating over own claim")
         if self.get_balance() < _bid - claim['amount']:
             raise InsufficientFundsError()
         d = self.update_metadata(metadata, claim['value'])
         claim_outpoint = ClaimOutpoint(claim['txid'], claim['nOut'])
         d.addCallback(
             lambda new_metadata: self._send_name_claim_update(
                 name, claim['claim_id'], claim_outpoint, new_metadata,
                 _bid))
         d.addCallback(lambda claim_out: claim_out.update(
             {'claim_id': claim['claim_id']}))
         return d
示例#11
0
 def check_fee(self, fee):
     validated_fee = FeeValidator(fee)
     max_key_fee = self.convert_max_fee()
     converted_fee = self.exchange_rate_manager.to_lbc(validated_fee).amount
     if converted_fee > self.wallet.get_balance():
         raise InsufficientFundsError('Unable to pay the key fee of %s' % converted_fee)
     if converted_fee > max_key_fee:
         raise KeyFeeAboveMaxAllowed('Key fee %s above max allowed %s' % (converted_fee,
                                                                          max_key_fee))
     return validated_fee
示例#12
0
 def _pay_key_fee(self):
     if self.fee is not None:
         fee_lbc = self.exchange_rate_manager.to_lbc(self.fee).amount
         reserved_points = self.wallet.reserve_points(self.fee.address, fee_lbc)
         if reserved_points is None:
             log.warning('Unable to pay the key fee of %s for %s', fee_lbc, self.resolved_name)
             # TODO: If we get here, nobody will know that there was an error
             #       as nobody actually cares about self._d
             return defer.fail(InsufficientFundsError())
         return self.wallet.send_points_to_address(reserved_points, fee_lbc)
     return defer.succeed(None)
示例#13
0
    def support_claim(self, name, claim_id, amount):
        def _parse_support_claim_out(claim_out):
            if not claim_out['success']:
                msg = 'Support of {}:{} failed: {}'.format(name, claim_id, claim_out['reason'])
                raise Exception(msg)
            claim_out = self._process_claim_out(claim_out)
            return defer.succeed(claim_out)

        if self.get_balance() < amount:
            raise InsufficientFundsError()

        d = self._support_claim(name, claim_id, amount)
        d.addCallback(lambda claim_out: _parse_support_claim_out(claim_out))
        return d
示例#14
0
 def check_fee_and_convert(self, fee):
     max_key_fee_amount = self.convert_max_fee()
     converted_fee_amount = self.exchange_rate_manager.convert_currency(fee.currency, "LBC",
                                                                        fee.amount)
     if converted_fee_amount > self.wallet.get_balance():
         raise InsufficientFundsError('Unable to pay the key fee of %s' % converted_fee_amount)
     if converted_fee_amount > max_key_fee_amount:
         raise KeyFeeAboveMaxAllowed('Key fee %s above max allowed %s' % (converted_fee_amount,
                                                                          max_key_fee_amount))
     converted_fee = {
         'currency': 'LBC',
         'amount': converted_fee_amount,
         'address': fee.address
     }
     return Fee(converted_fee)
示例#15
0
 def check_fee_and_convert(self, fee):
     max_key_fee_amount = self.convert_max_fee()
     converted_fee_amount = self.exchange_rate_manager.convert_currency(
         fee.currency, "LBC", fee.amount)
     if converted_fee_amount > (yield f2d(
             self.wallet.default_account.get_balance())):
         raise InsufficientFundsError('Unable to pay the key fee of %s' %
                                      converted_fee_amount)
     if converted_fee_amount > max_key_fee_amount and not self.disable_max_key_fee:
         raise KeyFeeAboveMaxAllowed(
             'Key fee {} above max allowed {}'.format(
                 converted_fee_amount, max_key_fee_amount))
     converted_fee = {
         'currency': 'LBC',
         'amount': converted_fee_amount,
         'address': fee.address
     }
     return Fee(converted_fee)
示例#16
0
文件: Wallet.py 项目: tml/lbry
    def claim_name(self, name, bid, metadata, certificate_id=None):
        """
        Claim a name, or update if name already claimed by user

        @param name: str, name to claim
        @param bid: float, bid amount
        @param metadata: ClaimDict compliant dict
        @param certificate_id: str (optional), claim id of channel certificate

        @return: Deferred which returns a dict containing below items
            txid - txid of the resulting transaction
            nout - nout of the resulting claim
            fee - transaction fee paid to make claim
            claim_id -  claim id of the claim
        """

        decoded = ClaimDict.load_dict(metadata)
        serialized = decoded.serialized

        if self.get_balance() < Decimal(bid):
            raise InsufficientFundsError()

        claim = yield self._send_name_claim(name, serialized.encode('hex'),
                                            bid, certificate_id)

        if not claim['success']:
            msg = 'Claim to name {} failed: {}'.format(name, claim['reason'])
            raise Exception(msg)

        claim = self._process_claim_out(claim)
        claim_outpoint = ClaimOutpoint(claim['txid'], claim['nout'])
        log.info("Saving metadata for claim %s %d", claim['txid'],
                 claim['nout'])
        yield self._update_claimid(claim['claim_id'], name, claim_outpoint)
        yield self._save_name_metadata(name, claim_outpoint,
                                       decoded.source_hash)
        defer.returnValue(claim)
 def send_next_request(self, peer, protocol):
     if self._finished_discovery(
     ) is False and self._should_send_request_to(peer) is True:
         p_r = None
         if not self._price_settled(protocol):
             p_r = self._get_price_request(peer, protocol)
         d_r = self._get_discover_request(peer)
         reserved_points = self._reserve_points(peer, protocol,
                                                d_r.max_pay_units)
         if reserved_points is not None:
             d1 = protocol.add_request(d_r)
             d1.addCallback(self._handle_discover_response, peer, d_r)
             d1.addBoth(self._pay_or_cancel_payment, protocol,
                        reserved_points)
             d1.addErrback(self._request_failed, peer)
             if p_r is not None:
                 d2 = protocol.add_request(p_r)
                 d2.addCallback(self._handle_price_response, peer, p_r,
                                protocol)
                 d2.addErrback(self._request_failed, peer)
             return defer.succeed(True)
         else:
             return defer.fail(InsufficientFundsError())
     return defer.succeed(False)
示例#18
0
    def start(self, stream_info, name):
        def _cancel(err):
            # this callback sequence gets cancelled in check_status if
            # it takes too long when that happens, we want the logic
            # to live in check_status
            if err.check(defer.CancelledError):
                return
            if self.checker:
                self.checker.stop()
            self.finished.errback(err)

        def _set_status(x, status):
            log.info("Download lbry://%s status changed to %s" % (self.resolved_name, status))
            self.code = next(s for s in STREAM_STAGES if s[0] == status)
            return x

        def get_downloader_factory(metadata):
            for factory in metadata.factories:
                if isinstance(factory, ManagedEncryptedFileDownloaderFactory):
                    return factory, metadata
            raise Exception('No suitable factory was found in {}'.format(metadata.factories))

        def make_downloader(args):
            factory, metadata = args
            return factory.make_downloader(metadata,
                                           [self.data_rate, True],
                                           self.payment_rate_manager,
                                           download_directory=self.download_directory,
                                           file_name=self.file_name)

        self.resolved_name = name
        self.stream_info = deepcopy(stream_info)
        self.description = self.stream_info['description']
        self.sd_hash = self.stream_info['sources']['lbry_sd_hash']

        if 'fee' in self.stream_info:
            self.fee = FeeValidator(self.stream_info['fee'])
            max_key_fee = self._convert_max_fee()
            converted_fee = self.exchange_rate_manager.to_lbc(self.fee).amount
            if converted_fee > self.wallet.get_balance():
                msg = "Insufficient funds to download lbry://{}. Need {:0.2f}, have {:0.2f}".format(
                    self.resolved_name, converted_fee, self.wallet.get_balance())
                raise InsufficientFundsError(msg)
            if converted_fee > max_key_fee:
                msg = "Key fee {:0.2f} above limit of {:0.2f} didn't download lbry://{}".format(
                    converted_fee, max_key_fee, self.resolved_name)
                raise KeyFeeAboveMaxAllowed(msg)
            log.info(
                "Key fee %f below limit of %f, downloading lbry://%s",
                converted_fee, max_key_fee, self.resolved_name)

        self.checker.start(1)

        self._d.addCallback(lambda _: _set_status(None, DOWNLOAD_METADATA_CODE))
        self._d.addCallback(lambda _: download_sd_blob(
            self.session, self.sd_hash, self.payment_rate_manager))
        self._d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
        self._d.addCallback(lambda r: _set_status(r, DOWNLOAD_RUNNING_CODE))
        self._d.addCallback(get_downloader_factory)
        self._d.addCallback(make_downloader)
        self._d.addCallbacks(self._start_download, _cancel)
        self._d.callback(None)

        return self.finished