diff --git a/lbrynet/core/PaymentRateManager.py b/lbrynet/core/PaymentRateManager.py index 914e21947..6e7c02047 100644 --- a/lbrynet/core/PaymentRateManager.py +++ b/lbrynet/core/PaymentRateManager.py @@ -1,5 +1,7 @@ from lbrynet.core.Strategy import get_default_strategy -from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, MIN_BLOB_INFO_PAYMENT_RATE +from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, MIN_BLOB_INFO_PAYMENT_RATE, is_generous_host +from decimal import Decimal + class BasePaymentRateManager(object): def __init__(self, rate=MIN_BLOB_DATA_PAYMENT_RATE, info_rate=MIN_BLOB_INFO_PAYMENT_RATE): @@ -34,7 +36,7 @@ class PaymentRateManager(object): class NegotiatedPaymentRateManager(object): - def __init__(self, base, availability_tracker, generous=True): + def __init__(self, base, availability_tracker, generous=is_generous_host): """ @param base: a BasePaymentRateManager @param availability_tracker: a BlobAvailabilityTracker @@ -70,4 +72,10 @@ class NegotiatedPaymentRateManager(object): self.points_paid += amount def record_offer_reply(self, peer, offer): - self.strategy.update_accepted_offers(peer, offer) \ No newline at end of file + self.strategy.update_accepted_offers(peer, offer) + + def price_limit_reached(self, peer): + if peer in self.strategy.pending_sent_offers: + offer = self.strategy.pending_sent_offers[peer] + return offer.is_too_low and round(Decimal.from_float(offer.rate), 5) >= round(self.strategy.max_rate, 5) + return False \ No newline at end of file diff --git a/lbrynet/core/Strategy.py b/lbrynet/core/Strategy.py index bb9059016..f25531652 100644 --- a/lbrynet/core/Strategy.py +++ b/lbrynet/core/Strategy.py @@ -1,5 +1,6 @@ from zope.interface import implementer from decimal import Decimal +from lbrynet.conf import is_generous_host from lbrynet.interfaces import INegotiationStrategy from lbrynet.core.Offer import Offer from lbrynet.core.PriceModel import MeanAvailabilityWeightedPrice @@ -15,14 +16,14 @@ class Strategy(object): """ implementer(INegotiationStrategy) - def __init__(self, price_model, max_rate, min_rate, is_generous=True): + def __init__(self, price_model, max_rate, min_rate, is_generous=is_generous_host): self.price_model = price_model self.is_generous = is_generous self.accepted_offers = {} self.pending_sent_offers = {} self.offers_sent = {} self.offers_received = {} - self.max_rate = max_rate or Decimal(self.price_model.base_price * 100) + self.max_rate = max_rate or Decimal(self.price_model.base_price * 50) self.min_rate = Decimal(min_rate) def _make_rate_offer(self, rates, offer_count): @@ -75,6 +76,7 @@ class Strategy(object): del self.accepted_offers[peer] if offer.is_accepted: self.accepted_offers.update({peer: offer}) + self.pending_sent_offers.update({peer: offer}) def _add_offer_sent(self, peer): turn = self.offers_sent.get(peer, 0) + 1 @@ -99,7 +101,7 @@ class BasicAvailabilityWeightedStrategy(Strategy): implementer(INegotiationStrategy) def __init__(self, blob_tracker, acceleration=1.25, deceleration=0.9, max_rate=None, min_rate=0.0, - is_generous=True, base_price=0.0001, alpha=1.0): + is_generous=is_generous_host, base_price=0.0001, alpha=1.0): price_model = MeanAvailabilityWeightedPrice(blob_tracker, base_price=base_price, alpha=alpha) Strategy.__init__(self, price_model, max_rate, min_rate, is_generous) self._acceleration = Decimal(acceleration) # rate of how quickly to ramp offer diff --git a/lbrynet/core/client/BlobRequester.py b/lbrynet/core/client/BlobRequester.py index 9e0ab7a86..a0e724c3c 100644 --- a/lbrynet/core/client/BlobRequester.py +++ b/lbrynet/core/client/BlobRequester.py @@ -54,6 +54,7 @@ class BlobRequester(object): self._protocol_offers = {} self._price_disagreements = [] # [Peer] self._protocol_tries = {} + self._maxed_out_peers = [] self._incompatible_peers = [] ######## IRequestCreator ######### @@ -120,7 +121,9 @@ class BlobRequester(object): def choose_best_peers(peers): bad_peers = self._get_bad_peers() - return [p for p in peers if not p in bad_peers] + without_bad_peers = [p for p in peers if not p in bad_peers] + without_maxed_out_peers = [p for p in without_bad_peers if p not in self._maxed_out_peers] + return without_maxed_out_peers d.addCallback(choose_best_peers) @@ -196,6 +199,10 @@ class RequestHelper(object): def unavailable_blobs(self): return self.requestor._unavailable_blobs[self.peer] + @property + def maxed_out_peers(self): + return self.requestor._maxed_out_peers + def update_local_score(self, score): self.requestor._update_local_score(self.peer, score) @@ -216,8 +223,16 @@ class RequestHelper(object): return reason def get_and_save_rate(self): + if self.payment_rate_manager.price_limit_reached(self.peer): + if self.peer not in self.maxed_out_peers: + self.maxed_out_peers.append(self.peer) + return None rate = self.protocol_prices.get(self.protocol) if rate is None: + if self.peer in self.payment_rate_manager.strategy.pending_sent_offers: + pending = self.payment_rate_manager.strategy.pending_sent_offers[self.peer] + if not pending.is_too_low and not pending.is_accepted: + return pending.rate rate = self.payment_rate_manager.get_rate_blob_data(self.peer, self.available_blobs) self.protocol_offers[self.protocol] = rate return rate @@ -343,7 +358,7 @@ class AvailabilityRequest(RequestHelper): class PriceRequest(RequestHelper): """Ask a peer if a certain price is acceptable""" def can_make_request(self): - if self.requestor._available_blobs: + if len(self.available_blobs) and not self.protocol in self.protocol_prices: return self.get_and_save_rate() is not None return False @@ -373,14 +388,14 @@ class PriceRequest(RequestHelper): assert self.protocol in self.protocol_offers offer = Offer(self.protocol_offers[self.protocol]) offer.handle(response_dict['blob_data_payment_rate']) - self.payment_rate_manager.record_offer_reply(self.peer.host, offer) + self.payment_rate_manager.record_offer_reply(self.peer, offer) if offer.is_accepted: log.info("Offered rate %f/mb accepted by %s", offer.rate, self.peer.host) self.protocol_prices[self.protocol] = offer.rate return True elif offer.is_too_low: log.debug("Offered rate %f/mb rejected by %s", offer.rate, self.peer.host) - return True + return not self.payment_rate_manager.price_limit_reached(self.peer) else: log.warning("Price disagreement") self.requestor._price_disagreements.append(self.peer)