diff --git a/lbrynet/core/LBRYMetadata.py b/lbrynet/core/LBRYMetadata.py index 133c34482..e57ee1ad6 100644 --- a/lbrynet/core/LBRYMetadata.py +++ b/lbrynet/core/LBRYMetadata.py @@ -2,11 +2,13 @@ import requests import json import time +from copy import deepcopy from googlefinance import getQuotes from lbrynet.conf import CURRENCIES import logging log = logging.getLogger(__name__) +log.setLevel(logging.INFO) BITTREX_FEE = 0.0025 @@ -26,23 +28,42 @@ FEE_REVISIONS = {'0.0.1': {'required': ['amount', 'address'], 'optional': []}} CURRENT_FEE_REVISION = '0.0.1' -class LBRYFee(object): - def __init__(self, fee_dict, rate_dict): - fee = LBRYFeeFormat(fee_dict) - - for currency in fee: - self.address = fee[currency]['address'] - if not isinstance(fee[currency]['amount'], float): - self.amount = float(fee[currency]['amount']) - else: - self.amount = fee[currency]['amount'] +class LBRYFeeFormat(dict): + def __init__(self, fee_dict): + dict.__init__(self) + self.fee_version = None + f = deepcopy(fee_dict) + assert len(fee_dict) == 1 + for currency in fee_dict: + assert currency in CURRENCIES, "Unsupported currency: %s" % str(currency) self.currency_symbol = currency + self.update({currency: {}}) + for version in FEE_REVISIONS: + for k in FEE_REVISIONS[version]['required']: + assert k in fee_dict[currency], "Missing required fee field: %s" % k + self[currency].update({k: f[currency].pop(k)}) + for k in FEE_REVISIONS[version]['optional']: + if k in fee_dict[currency]: + self[currency].update({k: f[currency].pop(k)}) + if not len(f): + self.fee_version = version + break + assert f[currency] == {}, "Unknown fee keys: %s" % json.dumps(f.keys()) - assert 'BTCLBC' in rate_dict and 'USDBTC' in rate_dict + self.amount = self[self.currency_symbol]['amount'] if isinstance(self[self.currency_symbol]['amount'], float) else float(self[self.currency_symbol]['amount']) + self.address = self[self.currency_symbol]['address'] + + +class LBRYFee(LBRYFeeFormat): + def __init__(self, fee_dict, rate_dict): + LBRYFeeFormat.__init__(self, fee_dict) + rates = deepcopy(rate_dict) + + assert 'BTCLBC' in rates and 'USDBTC' in rates for fx in rate_dict: - assert int(time.time()) - int(rate_dict[fx]['ts']) < 3600, "%s quote is out of date" % fx - self._USDBTC = {'spot': rate_dict['USDBTC']['spot'], 'ts': rate_dict['USDBTC']['ts']} - self._BTCLBC = {'spot': rate_dict['BTCLBC']['spot'], 'ts': rate_dict['BTCLBC']['ts']} + assert int(time.time()) - int(rates[fx]['ts']) < 3600, "%s quote is out of date" % fx + self._USDBTC = {'spot': rates['USDBTC']['spot'], 'ts': rates['USDBTC']['ts']} + self._BTCLBC = {'spot': rates['BTCLBC']['spot'], 'ts': rates['BTCLBC']['ts']} def to_lbc(self): r = None @@ -67,45 +88,31 @@ class LBRYFee(object): return r def _usd_to_btc(self, usd): + # log.error("usd to btc: " + str(usd)) + # log.error("%f * %f = %f" % (self._USDBTC['spot'], float(usd), self._USDBTC['spot'] * float(usd))) return self._USDBTC['spot'] * float(usd) def _btc_to_usd(self, btc): + # log.error("btc to usd: " + str(btc)) + # log.error("%f / %f = %f" % (float(btc), self._USDBTC['spot'], float(btc) / self._USDBTC['spot'])) return float(btc) / self._USDBTC['spot'] def _btc_to_lbc(self, btc): + # log.error("btc to lbc: " + str(btc)) + # log.error("%f * %f = %f" % (float(btc), self._BTCLBC['spot'], float(btc) * self._BTCLBC['spot'] / (1.0 - BITTREX_FEE))) return float(btc) * self._BTCLBC['spot'] / (1.0 - BITTREX_FEE) def _lbc_to_btc(self, lbc): + # log.error("lbc to btc: " + str(lbc)) + # log.error("%f / %f = %f" % (self._BTCLBC['spot'], float(lbc), self._BTCLBC['spot'] / float(lbc))) return self._BTCLBC['spot'] / float(lbc) -class LBRYFeeFormat(dict): - def __init__(self, fee_dict): - dict.__init__(self) - self.fee_version = None - f = fee_dict.copy() - assert len(fee_dict) == 1 - for currency in fee_dict: - assert currency in CURRENCIES, "Unsupported currency: %s" % str(currency) - self.update({currency: {}}) - for version in FEE_REVISIONS: - for k in FEE_REVISIONS[version]['required']: - assert k in fee_dict[currency], "Missing required fee field: %s" % k - self[currency].update({k: f[currency].pop(k)}) - for k in FEE_REVISIONS[version]['optional']: - if k in fee_dict[currency]: - self[currency].update({k: f[currency].pop(k)}) - if not len(f): - self.fee_version = version - break - assert f[currency] == {}, "Unknown fee keys: %s" % json.dumps(f.keys()) - - class Metadata(dict): def __init__(self, metadata): dict.__init__(self) self.metaversion = None - m = metadata.copy() + m = deepcopy(metadata) assert "sources" in metadata, "No sources given" for source in metadata['sources']: diff --git a/lbrynet/lbrynet_daemon/LBRYDaemon.py b/lbrynet/lbrynet_daemon/LBRYDaemon.py index c6a895f94..518dbdce6 100644 --- a/lbrynet/lbrynet_daemon/LBRYDaemon.py +++ b/lbrynet/lbrynet_daemon/LBRYDaemon.py @@ -1899,20 +1899,19 @@ class LBRYDaemon(jsonrpc.JSONRPC): file_path = p['file_path'] metadata = p['metadata'] - def _set_address(address): - metadata['fee']['address'] = address + d = defer.succeed(None) + + def _set_address(address, currency): + metadata['fee'][currency]['address'] = address return defer.succeed(None) if 'fee' in p: metadata['fee'] = p['fee'] - if 'address' not in metadata['fee']: - d = self.session.wallet.get_new_address() - d.addCallback(_set_address) - else: - d = defer.succeed(None) - else: - d = defer.succeed(None) - + assert len(metadata['fee']) == 1, "Too many fees" + for c in metadata['fee']: + if 'address' not in metadata['fee'][c]: + d = self.session.wallet.get_new_address() + d.addCallback(lambda addr: _set_address(addr, c)) pub = Publisher(self.session, self.lbry_file_manager, self.session.wallet) diff --git a/lbrynet/lbrynet_daemon/LBRYDownloader.py b/lbrynet/lbrynet_daemon/LBRYDownloader.py index 8d25aa56f..00c137869 100644 --- a/lbrynet/lbrynet_daemon/LBRYDownloader.py +++ b/lbrynet/lbrynet_daemon/LBRYDownloader.py @@ -3,6 +3,7 @@ import logging import os import sys +from copy import deepcopy from appdirs import user_data_dir from datetime import datetime from twisted.internet import defer @@ -58,7 +59,7 @@ class GetStream(object): self.sd_identifier = sd_identifier self.stream_hash = None self.max_key_fee = max_key_fee - self.metadata = None + self.stream_info = None self.stream_info_manager = None self.d = defer.Deferred(None) self.timeout = timeout @@ -86,20 +87,23 @@ class GetStream(object): def start(self, stream_info, name): self.resolved_name = name - self.metadata = stream_info - self.stream_hash = self.metadata['sources']['lbry_sd_hash'] + 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.metadata: - self.fee = LBRYFee(self.metadata['fee'], {'USDBTC': self.wallet._USDBTC, 'BTCLBC': self.wallet._BTCLBC}) + if 'fee' in self.stream_info: + self.fee = LBRYFee(self.stream_info['fee'], {'USDBTC': self.wallet._USDBTC, 'BTCLBC': self.wallet._BTCLBC}) if isinstance(self.max_key_fee, float): if self.fee.to_lbc() > self.max_key_fee: log.info("Key fee %f above limit of %f didn't download lbry://%s" % (self.fee.to_lbc(), self.max_key_fee, self.resolved_name)) return defer.fail(KeyFeeAboveMaxAllowed()) + log.info("Key fee %f below limit of %f, downloading lbry://%s" % (self.fee.to_lbc(), self.max_key_fee, self.resolved_name)) elif isinstance(self.max_key_fee, dict): - max_key = LBRYFee(self.max_key_fee, {'USDBTC': self.wallet._USDBTC, 'BTCLBC': self.wallet._BTCLBC}) + max_key = LBRYFee(deepcopy(self.max_key_fee), {'USDBTC': self.wallet._USDBTC, 'BTCLBC': self.wallet._BTCLBC}) if self.fee.to_lbc() > max_key.to_lbc(): log.info("Key fee %f above limit of %f didn't download lbry://%s" % (self.fee.to_lbc(), max_key.to_lbc(), self.resolved_name)) return defer.fail(KeyFeeAboveMaxAllowed()) + log.info("Key fee %f below limit of %f, downloading lbry://%s" % (self.fee.to_lbc(), max_key.to_lbc(), self.resolved_name)) def _cause_timeout(): self.timeout_counter = self.timeout * 2 @@ -130,20 +134,19 @@ class GetStream(object): def _start_download(self, downloader): def _pay_key_fee(): if self.fee is not None: - fee_lbc = self.fee.to_lbc() + fee_lbc = float(self.fee.to_lbc()) reserved_points = self.wallet.reserve_points(self.fee.address, fee_lbc) if reserved_points is None: return defer.fail(InsufficientFundsError()) - log.info("Key fee: %f --> %s" % (fee_lbc, self.fee.address)) - d = self.wallet.send_points_to_address(reserved_points, self.fee.address) - return d + return self.wallet.send_points_to_address(reserved_points, fee_lbc) return defer.succeed(None) + d = _pay_key_fee() + self.downloader = downloader self.download_path = os.path.join(downloader.download_directory, downloader.file_name) - d = _pay_key_fee() d.addCallback(lambda _: log.info("Downloading %s --> %s", self.stream_hash, self.downloader.file_name)) d.addCallback(lambda _: self.downloader.start())