diff --git a/lbrynet/core/LBRYcrdWallet.py b/lbrynet/core/LBRYcrdWallet.py index 982eebf10..4a1cc1c7f 100644 --- a/lbrynet/core/LBRYcrdWallet.py +++ b/lbrynet/core/LBRYcrdWallet.py @@ -1,6 +1,7 @@ from lbrynet.interfaces import IRequestCreator, IQueryHandlerFactory, IQueryHandler, ILBRYWallet from lbrynet.core.client.ClientRequest import ClientRequest from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError +from lbrynet.core.Error import InsufficientFundsError from lbrynet.core.sqlite_helpers import rerun_if_locked from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException from twisted.internet import threads, reactor, defer, task @@ -498,12 +499,20 @@ class LBRYcrdWallet(object): @_catch_connection_error def _claim_name(self, name, value, amount): rpc_conn = self._get_rpc_conn() - return str(rpc_conn.claimname(name, value, amount)) + try: + return str(rpc_conn.claimname(name, value, amount)) + except JSONRPCException as e: + if 'message' in e.error and e.error['message'] == "Insufficient funds": + raise InsufficientFundsError() + elif 'message' in e.error: + raise ValueError(e.error['message']) @_catch_connection_error def _get_status_of_claim(self, txhash, name, sd_hash): rpc_conn = self._get_rpc_conn() claims = rpc_conn.getclaimsfortx(txhash) + if claims is None: + claims = [] for claim in claims: if 'in claim trie' in claim: if 'name' in claim and str(claim['name']) == name and 'value' in claim: diff --git a/lbrynet/lbrynet_console/ConsoleControl.py b/lbrynet/lbrynet_console/ConsoleControl.py index 9c0bea6dc..0477154bd 100644 --- a/lbrynet/lbrynet_console/ConsoleControl.py +++ b/lbrynet/lbrynet_console/ConsoleControl.py @@ -36,6 +36,8 @@ class ConsoleControl(basic.LineReceiver): "If, for example, you are unable to download some files or\n" "your balance is showing 0 when you know it shouldn't be, it\n" "is likely that the culprit is the blockchain.\n\n" + "You should have received 1000 LBC the first time you ran\n" + "this program. If you did not, let us know!\n\n" "Welcome to lbrynet-console!") self.sendLine("") self.sendLine("Enter a command. Try 'get wonderfullife' or 'help' to see more options.") diff --git a/lbrynet/lbrynet_console/ControlHandlers.py b/lbrynet/lbrynet_console/ControlHandlers.py index f8c5a4d6e..9b2941f1c 100644 --- a/lbrynet/lbrynet_console/ControlHandlers.py +++ b/lbrynet/lbrynet_console/ControlHandlers.py @@ -54,6 +54,49 @@ class InvalidValueError(Exception): # prompt_description = None +class RoundedTime(object): + SECOND = 0 + MINUTE = 1 + HOUR = 2 + DAY = 3 + WEEK = 4 + units = ['second', 'minute', 'hour', 'day', 'week'] + + def __init__(self, unit, val): + assert unit < len(self.units) + self.unit = unit + self.val = val + + def __str__(self): + assert self.unit < len(self.units) + unit_str = self.units[self.unit] + if self.val != 1: + unit_str += "s" + return "%d %s" % (self.val, unit_str) + + +def get_time_behind_blockchain(best_block_time): + best_time = datetime.datetime.utcfromtimestamp(best_block_time) + diff = datetime.datetime.utcnow() - best_time + if diff.days > 0: + if diff.days >= 7: + val = diff.days // 7 + unit = RoundedTime.WEEK + else: + val = diff.days + unit = RoundedTime.DAY + elif diff.seconds >= 60 * 60: + val = diff.seconds // (60 * 60) + unit = RoundedTime.HOUR + elif diff.seconds >= 60: + val = diff.seconds // 60 + unit = RoundedTime.MINUTE + else: + val = diff.seconds + unit = RoundedTime.SECOND + return RoundedTime(unit, val) + + class CommandHandlerFactory(object): implements(ICommandHandlerFactory) priority = 0 @@ -269,32 +312,16 @@ class GetWalletBalances(CommandHandler): # assert line is None, "Show wallet balances should not be passed any arguments" # return True, self._get_wallet_balances() - def _show_time_behind_blockchain(self, best_block_time): - best_time = datetime.datetime.utcfromtimestamp(best_block_time) - diff = datetime.datetime.utcnow() - best_time - unit = None - val = None - if diff.days > 0: - if diff.days >= 7: - val = diff.days // 7 - unit = "week" - else: - val = diff.days - unit = "day" - elif diff.seconds >= 60 * 90: - if diff.seconds >= 60 * 60: - val = diff.seconds // (60 * 60) - unit = "hour" - if unit is not None: - if val != 1: - unit += "s" + def _show_time_behind_blockchain(self, rounded_time): + if rounded_time.unit >= RoundedTime.HOUR: self.console.sendLine("\n\nYour balance may be out of date. This application\n" - "is %d %s behind the LBC blockchain.\n\n" % (val, unit)) + "is %s behind the LBC blockchain.\n\n" % str(rounded_time)) else: - self.console.sendLine("\n\n") + self.console.sendLine("") def _log_recent_blocktime_error(self, err): log.error("An error occurred looking up the most recent blocktime: %s", err.getTraceback()) + self.console.sendLine("") def _get_wallet_balances(self): d = self.wallet.get_balance() @@ -302,12 +329,13 @@ class GetWalletBalances(CommandHandler): def format_balance(balance): if balance == 0: balance = 0 - balance_string = "balance: " + str(balance) + " LBC\n" + balance_string = "balance: " + str(balance) + " LBC" self.console.sendLine(balance_string) d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) d.addCallback(self._show_time_behind_blockchain) d.addErrback(self._log_recent_blocktime_error) - d.chainDeferred(self.finished_deferred) + return d d.addCallback(format_balance) return d @@ -429,9 +457,10 @@ class AddStream(CommandHandler): cancel_prompt = "Trying to locate the stream's metadata. Type \"cancel\" to cancel..." canceled_message = "Canceled downloading." - def __init__(self, console, sd_identifier, base_payment_rate_manager): + def __init__(self, console, sd_identifier, base_payment_rate_manager, wallet): CommandHandler.__init__(self, console) self.sd_identifier = sd_identifier + self.wallet = wallet self.loading_metadata_deferred = None self.metadata = None self.factory = None @@ -690,6 +719,10 @@ class AddStream(CommandHandler): def _handle_download_error(self, err): if err.check(InsufficientFundsError): self.console.sendLine("Download stopped due to insufficient funds.") + d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) + d.addCallback(self._show_time_behind_blockchain_download) + d.addErrback(self._log_recent_blockchain_time_error_download) else: log.error("An unexpected error has caused the download to stop: %s" % err.getTraceback()) self.console.sendLine("An unexpected error has caused the download to stop. See console.log for details.") @@ -698,6 +731,15 @@ class AddStream(CommandHandler): return self.factory.make_downloader(self.metadata, self.options_chosen, self.payment_rate_manager) + def _show_time_behind_blockchain_download(self, rounded_time): + if rounded_time.unit >= RoundedTime.HOUR: + self.console.sendLine("\nThis application is %s behind the LBC blockchain, so some of your\n" + "funds may not be available. Use 'get-blockchain-status' to check if\n" + "your application is up to date with the blockchain." % str(rounded_time)) + + def _log_recent_blockchain_time_error_download(self, err): + log.error("An error occurred trying to look up the most recent blocktime: %s", err.getTraceback()) + class AddStreamFromSD(AddStream): #prompt_description = "Add a stream from a stream descriptor file" @@ -721,8 +763,8 @@ class AddStreamFromHash(AddStream): #prompt_description = "Add a stream from a hash" #line_prompt = "Stream descriptor hash:" - def __init__(self, console, sd_identifier, session): - AddStream.__init__(self, console, sd_identifier, session.base_payment_rate_manager) + def __init__(self, console, sd_identifier, session, wallet): + AddStream.__init__(self, console, sd_identifier, session.base_payment_rate_manager, wallet) self.session = session def start(self, sd_hash): @@ -739,8 +781,13 @@ class AddStreamFromHash(AddStream): self.finished_deferred.callback(None) return if err.check(InsufficientFundsError): - self.console.sendLine("Insufficient funds to download the metadata blob.\n\n") - self.finished_deferred.callback(None) + self.console.sendLine("Insufficient funds to download the metadata blob.") + d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) + d.addCallback(self._show_time_behind_blockchain_download) + d.addErrback(self._log_recent_blockchain_time_error_download) + d.addCallback(lambda _: self.console.sendLine("\n")) + d.chainDeferred(self.finished_deferred) return return AddStream._handle_load_failed(self, err) @@ -760,7 +807,7 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): #line_prompt = "Short name:" def __init__(self, console, sd_identifier, session, wallet): - AddStreamFromHash.__init__(self, console, sd_identifier, session) + AddStreamFromHash.__init__(self, console, sd_identifier, session, wallet) self.wallet = wallet self.resolved_name = None self.description = None @@ -790,36 +837,23 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): self.key_fee = None self.key_fee_address = stream_info.get('key_fee_address', None) return stream_info['stream_hash'] - d = self.wallet.get_stream_info_for_name(name) + d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) + d.addCallback(self._show_time_behind_blockchain_resolve) + d.addErrback(self._log_recent_blockchain_time_error_resolve) + d.addCallback(lambda _: self.wallet.get_stream_info_for_name(name)) d.addCallback(get_name_from_info) return d - def _show_time_behind_blockchain(self, best_block_time): - best_time = datetime.datetime.utcfromtimestamp(best_block_time) - diff = datetime.datetime.utcnow() - best_time - unit = None - val = None - if diff.days > 0: - if diff.days >= 7: - val = diff.days // 7 - unit = "week" - else: - val = diff.days - unit = "day" - elif diff.seconds >= 60 * 90: - if diff.seconds >= 60 * 60: - val = diff.seconds // (60 * 60) - unit = "hour" - if unit is not None: - if val != 1: - unit += "s" - self.console.sendLine("\nThis application is %d %s behind the LBC blockchain, which may be\n" - "preventing this name from being resolved. Use 'get-blockchain-status'\n" - "to check if your application is up to date with the blockchain.\n\n" % (val, unit)) + def _show_time_behind_blockchain_resolve(self, rounded_time): + if rounded_time.unit >= RoundedTime.HOUR: + self.console.sendLine("\nThis application is %s behind the LBC blockchain, which may be\n" + "preventing this name from being resolved correctly. Use 'get-blockchain-status'\n" + "to check if your application is up to date with the blockchain.\n\n" % str(rounded_time)) else: - self.console.sendLine("\n\n") + self.console.sendLine("\n") - def _log_recent_blockchain_time_error(self, err): + def _log_recent_blockchain_time_error_resolve(self, err): log.error("An error occurred trying to look up the most recent blocktime: %s", err.getTraceback()) def _handle_load_failed(self, err): @@ -832,10 +866,7 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash): return else: self.console.sendLine("The name %s could not be found." % err.getErrorMessage()) - d = self.wallet.get_most_recent_blocktime() - d.addCallback(self._show_time_behind_blockchain) - d.addErrback(self._log_recent_blockchain_time_error) - d.chainDeferred(self.finished_deferred) + self.finished_deferred.callback(True) return elif err.check(InvalidBlobHashError): self.console.sendLine("The metadata for this name is invalid. The stream cannot be downloaded.\n\n") @@ -1768,10 +1799,29 @@ class Publish(CommandHandler): message = "Finished publishing %s to %s. The txid of the LBRYcrd claim is %s." self.console.sendLine(message % (str(self.file_name), str(self.publish_name), str(self.tx_hash))) + def _show_time_behind_blockchain(self, rounded_time): + if rounded_time.unit >= RoundedTime.HOUR: + self.console.sendLine("This application is %s behind the LBC blockchain\n" + "and therefore may not have all of the funds you expect\n" + "available at this time." % str(rounded_time)) + + def _log_best_blocktime_error(self, err): + log.error("An error occurred checking the best time of the blockchain: %s", err.getTraceback()) + def _show_publish_error(self, err): message = "An error occurred publishing %s to %s. Error: %s." - self.console.sendLine(message % (str(self.file_name), str(self.publish_name), err.getErrorMessage())) + if err.check(InsufficientFundsError): + d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) + d.addCallback(self._show_time_behind_blockchain) + d.addErrback(self._log_best_blocktime_error) + error_message = "Insufficient funds" + else: + d = defer.succeed(True) + error_message = err.getErrorMessage() + self.console.sendLine(message % (str(self.file_name), str(self.publish_name), error_message)) log.error(message, str(self.file_name), str(self.publish_name), err.getTraceback()) + return d def _do_publish(self): d = create_lbry_file(self.session, self.lbry_file_manager, self.file_name, open(self.file_path)) @@ -2480,35 +2530,19 @@ class BlockchainStatus(CommandHandler): def start(self): d = self.wallet.get_most_recent_blocktime() + d.addCallback(get_time_behind_blockchain) d.addCallbacks(self._show_time_behind_blockchain, self._show_error) d.chainDeferred(self.finished_deferred) return d - def _show_time_behind_blockchain(self, best_block_time): - best_time = datetime.datetime.utcfromtimestamp(best_block_time) - diff = datetime.datetime.utcnow() - best_time - unit = None - val = None - if diff.days > 0: - if diff.days >= 7: - val = diff.days // 7 - unit = "week" - else: - val = diff.days - unit = "day" - elif diff.seconds >= 60 * 90: - if diff.seconds >= 60 * 60: - val = diff.seconds // (60 * 60) - unit = "hour" - if unit is not None: - if val != 1: - unit += "s" - self.console.sendLine("This application is %d %s behind the LBC blockchain." % (val, unit)) + def _show_time_behind_blockchain(self, rounded_time): + if rounded_time.unit >= RoundedTime.HOUR: + self.console.sendLine("This application is %s behind the LBC blockchain." % str(rounded_time)) else: self.console.sendLine("This application is up to date with the LBC blockchain.") def _show_error(self, err): - logging.error(err.getTraceback()) + log.error(err.getTraceback()) self.console.sendLine("Unable to determine the status of the blockchain.") diff --git a/lbrynet/lbrynet_console/LBRYConsole.py b/lbrynet/lbrynet_console/LBRYConsole.py index 2b284597b..dc4af02d8 100644 --- a/lbrynet/lbrynet_console/LBRYConsole.py +++ b/lbrynet/lbrynet_console/LBRYConsole.py @@ -353,7 +353,8 @@ class LBRYConsole(): ShutDownFactory(self), PeerStatsAndSettingsChooserFactory(self.session.peer_manager), LBRYFileStatusFactory(self.lbry_file_manager), - AddStreamFromSDFactory(self.sd_identifier, self.session.base_payment_rate_manager), + AddStreamFromSDFactory(self.sd_identifier, self.session.base_payment_rate_manager, + self.session.wallet), DeleteLBRYFileChooserFactory(self.lbry_file_metadata_manager, self.session.blob_manager, self.lbry_file_manager), ToggleLBRYFileRunningChooserFactory(self.lbry_file_manager), @@ -365,7 +366,7 @@ class LBRYConsole(): CreatePlainStreamDescriptorChooserFactory(self.lbry_file_manager), ShowLBRYFileStreamHashChooserFactory(self.lbry_file_manager), ModifyLBRYFileOptionsChooserFactory(self.lbry_file_manager), - AddStreamFromHashFactory(self.sd_identifier, self.session), + AddStreamFromHashFactory(self.sd_identifier, self.session, self.session.wallet), StatusFactory(self, self.session.rate_limiter, self.lbry_file_manager, self.session.blob_manager, self.session.wallet if self.wallet_type == 'lbrycrd' else None), # AutoFetcherStartFactory(self.autofetcher),