show if the application is behind on the blockchain if an error occurs that could be caused by that

This commit is contained in:
Jimmy Kiselak 2015-12-15 14:42:29 -05:00
parent 6d2e5af6bc
commit a948335cb9
4 changed files with 129 additions and 83 deletions

View file

@ -1,6 +1,7 @@
from lbrynet.interfaces import IRequestCreator, IQueryHandlerFactory, IQueryHandler, ILBRYWallet from lbrynet.interfaces import IRequestCreator, IQueryHandlerFactory, IQueryHandler, ILBRYWallet
from lbrynet.core.client.ClientRequest import ClientRequest from lbrynet.core.client.ClientRequest import ClientRequest
from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError
from lbrynet.core.Error import InsufficientFundsError
from lbrynet.core.sqlite_helpers import rerun_if_locked from lbrynet.core.sqlite_helpers import rerun_if_locked
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
from twisted.internet import threads, reactor, defer, task from twisted.internet import threads, reactor, defer, task
@ -498,12 +499,20 @@ class LBRYcrdWallet(object):
@_catch_connection_error @_catch_connection_error
def _claim_name(self, name, value, amount): def _claim_name(self, name, value, amount):
rpc_conn = self._get_rpc_conn() rpc_conn = self._get_rpc_conn()
try:
return str(rpc_conn.claimname(name, value, amount)) 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 @_catch_connection_error
def _get_status_of_claim(self, txhash, name, sd_hash): def _get_status_of_claim(self, txhash, name, sd_hash):
rpc_conn = self._get_rpc_conn() rpc_conn = self._get_rpc_conn()
claims = rpc_conn.getclaimsfortx(txhash) claims = rpc_conn.getclaimsfortx(txhash)
if claims is None:
claims = []
for claim in claims: for claim in claims:
if 'in claim trie' in claim: if 'in claim trie' in claim:
if 'name' in claim and str(claim['name']) == name and 'value' in claim: if 'name' in claim and str(claim['name']) == name and 'value' in claim:

View file

@ -36,6 +36,8 @@ class ConsoleControl(basic.LineReceiver):
"If, for example, you are unable to download some files or\n" "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" "your balance is showing 0 when you know it shouldn't be, it\n"
"is likely that the culprit is the blockchain.\n\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!") "Welcome to lbrynet-console!")
self.sendLine("") self.sendLine("")
self.sendLine("Enter a command. Try 'get wonderfullife' or 'help' to see more options.") self.sendLine("Enter a command. Try 'get wonderfullife' or 'help' to see more options.")

View file

@ -54,6 +54,49 @@ class InvalidValueError(Exception):
# prompt_description = None # 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): class CommandHandlerFactory(object):
implements(ICommandHandlerFactory) implements(ICommandHandlerFactory)
priority = 0 priority = 0
@ -269,32 +312,16 @@ class GetWalletBalances(CommandHandler):
# assert line is None, "Show wallet balances should not be passed any arguments" # assert line is None, "Show wallet balances should not be passed any arguments"
# return True, self._get_wallet_balances() # return True, self._get_wallet_balances()
def _show_time_behind_blockchain(self, best_block_time): def _show_time_behind_blockchain(self, rounded_time):
best_time = datetime.datetime.utcfromtimestamp(best_block_time) if rounded_time.unit >= RoundedTime.HOUR:
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("\n\nYour balance may be out of date. This application\n" 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: else:
self.console.sendLine("\n\n") self.console.sendLine("")
def _log_recent_blocktime_error(self, err): def _log_recent_blocktime_error(self, err):
log.error("An error occurred looking up the most recent blocktime: %s", err.getTraceback()) log.error("An error occurred looking up the most recent blocktime: %s", err.getTraceback())
self.console.sendLine("")
def _get_wallet_balances(self): def _get_wallet_balances(self):
d = self.wallet.get_balance() d = self.wallet.get_balance()
@ -302,12 +329,13 @@ class GetWalletBalances(CommandHandler):
def format_balance(balance): def format_balance(balance):
if balance == 0: if balance == 0:
balance = 0 balance = 0
balance_string = "balance: " + str(balance) + " LBC\n" balance_string = "balance: " + str(balance) + " LBC"
self.console.sendLine(balance_string) self.console.sendLine(balance_string)
d = self.wallet.get_most_recent_blocktime() d = self.wallet.get_most_recent_blocktime()
d.addCallback(get_time_behind_blockchain)
d.addCallback(self._show_time_behind_blockchain) d.addCallback(self._show_time_behind_blockchain)
d.addErrback(self._log_recent_blocktime_error) d.addErrback(self._log_recent_blocktime_error)
d.chainDeferred(self.finished_deferred) return d
d.addCallback(format_balance) d.addCallback(format_balance)
return d return d
@ -429,9 +457,10 @@ class AddStream(CommandHandler):
cancel_prompt = "Trying to locate the stream's metadata. Type \"cancel\" to cancel..." cancel_prompt = "Trying to locate the stream's metadata. Type \"cancel\" to cancel..."
canceled_message = "Canceled downloading." 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) CommandHandler.__init__(self, console)
self.sd_identifier = sd_identifier self.sd_identifier = sd_identifier
self.wallet = wallet
self.loading_metadata_deferred = None self.loading_metadata_deferred = None
self.metadata = None self.metadata = None
self.factory = None self.factory = None
@ -690,6 +719,10 @@ class AddStream(CommandHandler):
def _handle_download_error(self, err): def _handle_download_error(self, err):
if err.check(InsufficientFundsError): if err.check(InsufficientFundsError):
self.console.sendLine("Download stopped due to insufficient funds.") 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: else:
log.error("An unexpected error has caused the download to stop: %s" % err.getTraceback()) 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.") 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, return self.factory.make_downloader(self.metadata, self.options_chosen,
self.payment_rate_manager) 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): class AddStreamFromSD(AddStream):
#prompt_description = "Add a stream from a stream descriptor file" #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" #prompt_description = "Add a stream from a hash"
#line_prompt = "Stream descriptor hash:" #line_prompt = "Stream descriptor hash:"
def __init__(self, console, sd_identifier, session): def __init__(self, console, sd_identifier, session, wallet):
AddStream.__init__(self, console, sd_identifier, session.base_payment_rate_manager) AddStream.__init__(self, console, sd_identifier, session.base_payment_rate_manager, wallet)
self.session = session self.session = session
def start(self, sd_hash): def start(self, sd_hash):
@ -739,8 +781,13 @@ class AddStreamFromHash(AddStream):
self.finished_deferred.callback(None) self.finished_deferred.callback(None)
return return
if err.check(InsufficientFundsError): if err.check(InsufficientFundsError):
self.console.sendLine("Insufficient funds to download the metadata blob.\n\n") self.console.sendLine("Insufficient funds to download the metadata blob.")
self.finished_deferred.callback(None) 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
return AddStream._handle_load_failed(self, err) return AddStream._handle_load_failed(self, err)
@ -760,7 +807,7 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash):
#line_prompt = "Short name:" #line_prompt = "Short name:"
def __init__(self, console, sd_identifier, session, wallet): 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.wallet = wallet
self.resolved_name = None self.resolved_name = None
self.description = None self.description = None
@ -790,36 +837,23 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash):
self.key_fee = None self.key_fee = None
self.key_fee_address = stream_info.get('key_fee_address', None) self.key_fee_address = stream_info.get('key_fee_address', None)
return stream_info['stream_hash'] 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) d.addCallback(get_name_from_info)
return d return d
def _show_time_behind_blockchain(self, best_block_time): def _show_time_behind_blockchain_resolve(self, rounded_time):
best_time = datetime.datetime.utcfromtimestamp(best_block_time) if rounded_time.unit >= RoundedTime.HOUR:
diff = datetime.datetime.utcnow() - best_time self.console.sendLine("\nThis application is %s behind the LBC blockchain, which may be\n"
unit = None "preventing this name from being resolved correctly. Use 'get-blockchain-status'\n"
val = None "to check if your application is up to date with the blockchain.\n\n" % str(rounded_time))
if diff.days > 0:
if diff.days >= 7:
val = diff.days // 7
unit = "week"
else: else:
val = diff.days self.console.sendLine("\n")
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))
else:
self.console.sendLine("\n\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()) log.error("An error occurred trying to look up the most recent blocktime: %s", err.getTraceback())
def _handle_load_failed(self, err): def _handle_load_failed(self, err):
@ -832,10 +866,7 @@ class AddStreamFromLBRYcrdName(AddStreamFromHash):
return return
else: else:
self.console.sendLine("The name %s could not be found." % err.getErrorMessage()) self.console.sendLine("The name %s could not be found." % err.getErrorMessage())
d = self.wallet.get_most_recent_blocktime() self.finished_deferred.callback(True)
d.addCallback(self._show_time_behind_blockchain)
d.addErrback(self._log_recent_blockchain_time_error)
d.chainDeferred(self.finished_deferred)
return return
elif err.check(InvalidBlobHashError): elif err.check(InvalidBlobHashError):
self.console.sendLine("The metadata for this name is invalid. The stream cannot be downloaded.\n\n") 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." 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))) 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): def _show_publish_error(self, err):
message = "An error occurred publishing %s to %s. Error: %s." 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()) log.error(message, str(self.file_name), str(self.publish_name), err.getTraceback())
return d
def _do_publish(self): def _do_publish(self):
d = create_lbry_file(self.session, self.lbry_file_manager, self.file_name, open(self.file_path)) 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): def start(self):
d = self.wallet.get_most_recent_blocktime() d = self.wallet.get_most_recent_blocktime()
d.addCallback(get_time_behind_blockchain)
d.addCallbacks(self._show_time_behind_blockchain, self._show_error) d.addCallbacks(self._show_time_behind_blockchain, self._show_error)
d.chainDeferred(self.finished_deferred) d.chainDeferred(self.finished_deferred)
return d return d
def _show_time_behind_blockchain(self, best_block_time): def _show_time_behind_blockchain(self, rounded_time):
best_time = datetime.datetime.utcfromtimestamp(best_block_time) if rounded_time.unit >= RoundedTime.HOUR:
diff = datetime.datetime.utcnow() - best_time self.console.sendLine("This application is %s behind the LBC blockchain." % str(rounded_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))
else: else:
self.console.sendLine("This application is up to date with the LBC blockchain.") self.console.sendLine("This application is up to date with the LBC blockchain.")
def _show_error(self, err): def _show_error(self, err):
logging.error(err.getTraceback()) log.error(err.getTraceback())
self.console.sendLine("Unable to determine the status of the blockchain.") self.console.sendLine("Unable to determine the status of the blockchain.")

View file

@ -353,7 +353,8 @@ class LBRYConsole():
ShutDownFactory(self), ShutDownFactory(self),
PeerStatsAndSettingsChooserFactory(self.session.peer_manager), PeerStatsAndSettingsChooserFactory(self.session.peer_manager),
LBRYFileStatusFactory(self.lbry_file_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, DeleteLBRYFileChooserFactory(self.lbry_file_metadata_manager, self.session.blob_manager,
self.lbry_file_manager), self.lbry_file_manager),
ToggleLBRYFileRunningChooserFactory(self.lbry_file_manager), ToggleLBRYFileRunningChooserFactory(self.lbry_file_manager),
@ -365,7 +366,7 @@ class LBRYConsole():
CreatePlainStreamDescriptorChooserFactory(self.lbry_file_manager), CreatePlainStreamDescriptorChooserFactory(self.lbry_file_manager),
ShowLBRYFileStreamHashChooserFactory(self.lbry_file_manager), ShowLBRYFileStreamHashChooserFactory(self.lbry_file_manager),
ModifyLBRYFileOptionsChooserFactory(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, StatusFactory(self, self.session.rate_limiter, self.lbry_file_manager,
self.session.blob_manager, self.session.wallet if self.wallet_type == 'lbrycrd' else None), self.session.blob_manager, self.session.wallet if self.wallet_type == 'lbrycrd' else None),
# AutoFetcherStartFactory(self.autofetcher), # AutoFetcherStartFactory(self.autofetcher),