From 4b45a3184a557c16fe358af54564121a63d0c0cd Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Mon, 14 Sep 2015 23:55:04 +0200 Subject: [PATCH] Enhance behavior in offline mode --- src/cutecoin/core/community.py | 1 + src/cutecoin/core/graph.py | 277 ++++++++++++------------ src/cutecoin/core/net/api/bma/access.py | 41 ++-- src/cutecoin/core/registry/identity.py | 18 +- src/cutecoin/core/txhistory.py | 117 +++++----- src/cutecoin/core/wallet.py | 26 +-- src/cutecoin/gui/certification.py | 5 + src/cutecoin/gui/community_tile.py | 81 ++++--- src/cutecoin/gui/community_view.py | 41 +++- src/cutecoin/gui/identities_tab.py | 36 +-- src/cutecoin/gui/transactions_tab.py | 30 +-- src/cutecoin/models/identities.py | 8 +- src/cutecoin/models/txhistory.py | 9 +- src/cutecoin/tools/exceptions.py | 4 +- 14 files changed, 384 insertions(+), 310 deletions(-) diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 7b322b95..ae85f2e1 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -204,6 +204,7 @@ class Community(QObject): if '404' in e: return 0 except NoPeerAvailable as e: + logging.debug(str(e)) return 0 @property diff --git a/src/cutecoin/core/graph.py b/src/cutecoin/core/graph.py index 96576a13..682fbdf0 100644 --- a/src/cutecoin/core/graph.py +++ b/src/cutecoin/core/graph.py @@ -4,6 +4,7 @@ import asyncio from PyQt5.QtCore import QLocale, QDateTime from ..core.registry import Identity, BlockchainState from ..tools.decorators import asyncify +from ..tools.exceptions import NoPeerAvailable from cutecoin.gui.views.wot import NODE_STATUS_HIGHLIGHTED, NODE_STATUS_OUT, ARC_STATUS_STRONG, ARC_STATUS_WEAK @@ -160,75 +161,78 @@ class Graph(object): :return: """ if self.community: - yield from self.refresh_signature_validity() - # Â add certifiers of uid - for certifier in tuple(certifier_list): - # add only valid certification... - if (time.time() - certifier['cert_time']) > self.signature_validity: - continue - # new node - if certifier['identity'].pubkey not in self._graph.keys(): - node_status = 0 - is_member = yield from certifier['identity'].is_member(self.community) - if certifier['identity'].pubkey == identity_account.pubkey: - node_status += NODE_STATUS_HIGHLIGHTED - if is_member is False: - node_status += NODE_STATUS_OUT - self._graph[certifier['identity'].pubkey] = { - 'id': certifier['identity'].pubkey, - 'arcs': list(), - 'text': certifier['identity'].uid, - 'tooltip': certifier['identity'].pubkey, - 'status': node_status, - 'connected': [identity.pubkey] - } - - # keep only the latest certification - if self._graph[certifier['identity'].pubkey]['arcs']: - if certifier['cert_time'] < self._graph[certifier['identity'].pubkey]['arcs'][0]['cert_time']: + try: + yield from self.refresh_signature_validity() + # Â add certifiers of uid + for certifier in tuple(certifier_list): + # add only valid certification... + if (time.time() - certifier['cert_time']) > self.signature_validity: continue - # display validity status - if (time.time() - certifier['cert_time']) > self.ARC_STATUS_STRONG_time: - arc_status = ARC_STATUS_WEAK - else: - arc_status = ARC_STATUS_STRONG + # new node + if certifier['identity'].pubkey not in self._graph.keys(): + node_status = 0 + is_member = yield from certifier['identity'].is_member(self.community) + if certifier['identity'].pubkey == identity_account.pubkey: + node_status += NODE_STATUS_HIGHLIGHTED + if is_member is False: + node_status += NODE_STATUS_OUT + self._graph[certifier['identity'].pubkey] = { + 'id': certifier['identity'].pubkey, + 'arcs': list(), + 'text': certifier['identity'].uid, + 'tooltip': certifier['identity'].pubkey, + 'status': node_status, + 'connected': [identity.pubkey] + } - arc = { - 'id': identity.pubkey, - 'status': arc_status, - 'tooltip': QLocale.toString( - QLocale(), - QDateTime.fromTime_t(certifier['cert_time'] + self.signature_validity).date(), - QLocale.dateFormat(QLocale(), QLocale.ShortFormat) - ), - 'cert_time': certifier['cert_time'] - } + # keep only the latest certification + if self._graph[certifier['identity'].pubkey]['arcs']: + if certifier['cert_time'] < self._graph[certifier['identity'].pubkey]['arcs'][0]['cert_time']: + continue + # display validity status + if (time.time() - certifier['cert_time']) > self.ARC_STATUS_STRONG_time: + arc_status = ARC_STATUS_WEAK + else: + arc_status = ARC_STATUS_STRONG - if certifier['block_number']: - current_validations = self.community.network.latest_block_number - certifier['block_number'] - else: - current_validations = 0 - members_pubkeys = yield from self.community.members_pubkeys() - max_validation = self.community.network.fork_window(members_pubkeys) + 1 + arc = { + 'id': identity.pubkey, + 'status': arc_status, + 'tooltip': QLocale.toString( + QLocale(), + QDateTime.fromTime_t(certifier['cert_time'] + self.signature_validity).date(), + QLocale.dateFormat(QLocale(), QLocale.ShortFormat) + ), + 'cert_time': certifier['cert_time'] + } - # Current validation can be negative if self.community.network.latest_block_number - # is not refreshed yet - if max_validation > current_validations > 0: - if self.app.preferences['expert_mode']: - arc['validation_text'] = "{0}/{1}".format(current_validations, - max_validation) + if certifier['block_number']: + current_validations = self.community.network.latest_block_number - certifier['block_number'] else: - validation = current_validations / max_validation * 100 - arc['validation_text'] = "{0} %".format(QLocale().toString(float(validation), 'f', 0)) - else: - arc['validation_text'] = None + current_validations = 0 + members_pubkeys = yield from self.community.members_pubkeys() + max_validation = self.community.network.fork_window(members_pubkeys) + 1 - # Â add arc to certifier - self._graph[certifier['identity'].pubkey]['arcs'].append(arc) - # if certifier node not in identity nodes - if certifier['identity'].pubkey not in tuple(self._graph[identity.pubkey]['connected']): - #Â add certifier node to identity node - self._graph[identity.pubkey]['connected'].append(certifier['identity'].pubkey) + # Current validation can be negative if self.community.network.latest_block_number + # is not refreshed yet + if max_validation > current_validations > 0: + if self.app.preferences['expert_mode']: + arc['validation_text'] = "{0}/{1}".format(current_validations, + max_validation) + else: + validation = current_validations / max_validation * 100 + arc['validation_text'] = "{0} %".format(QLocale().toString(float(validation), 'f', 0)) + else: + arc['validation_text'] = None + + # Â add arc to certifier + self._graph[certifier['identity'].pubkey]['arcs'].append(arc) + # if certifier node not in identity nodes + if certifier['identity'].pubkey not in tuple(self._graph[identity.pubkey]['connected']): + #Â add certifier node to identity node + self._graph[identity.pubkey]['connected'].append(certifier['identity'].pubkey) + except NoPeerAvailable as e: + logging.debug(str(e)) @asyncio.coroutine def add_certified_list(self, certified_list, identity, identity_account): @@ -239,81 +243,86 @@ class Graph(object): :param identity identity_account: Account identity instance :return: """ - yield from self.refresh_signature_validity() - # add certified by uid - for certified in tuple(certified_list): - # add only valid certification... - if (time.time() - certified['cert_time']) > self.signature_validity: - continue - if certified['identity'].pubkey not in self._graph.keys(): - node_status = 0 - is_member = yield from certified['identity'].is_member(self.community) - if certified['identity'].pubkey == identity_account.pubkey: - node_status += NODE_STATUS_HIGHLIGHTED - if is_member is False: - node_status += NODE_STATUS_OUT - self._graph[certified['identity'].pubkey] = { - 'id': certified['identity'].pubkey, - 'arcs': list(), - 'text': certified['identity'].uid, - 'tooltip': certified['identity'].pubkey, - 'status': node_status, - 'connected': [identity.pubkey] - } - # display validity status - if (time.time() - certified['cert_time']) > self.ARC_STATUS_STRONG_time: - arc_status = ARC_STATUS_WEAK - else: - arc_status = ARC_STATUS_STRONG - arc = { - 'id': certified['identity'].pubkey, - 'status': arc_status, - 'tooltip': QLocale.toString( - QLocale(), - QDateTime.fromTime_t(certified['cert_time'] + self.signature_validity).date(), - QLocale.dateFormat(QLocale(), QLocale.ShortFormat) - ), - 'cert_time': certified['cert_time'] - } - if certified['block_number']: - current_validations = self.community.network.latest_block_number - certified['block_number'] - else: - current_validations = 0 - members_pubkeys = yield from self.community.members_pubkeys() - max_validations = self.community.network.fork_window(members_pubkeys) + 1 + if self.community: + try: + yield from self.refresh_signature_validity() + # add certified by uid + for certified in tuple(certified_list): + # add only valid certification... + if (time.time() - certified['cert_time']) > self.signature_validity: + continue + if certified['identity'].pubkey not in self._graph.keys(): + node_status = 0 + is_member = yield from certified['identity'].is_member(self.community) + if certified['identity'].pubkey == identity_account.pubkey: + node_status += NODE_STATUS_HIGHLIGHTED + if is_member is False: + node_status += NODE_STATUS_OUT + self._graph[certified['identity'].pubkey] = { + 'id': certified['identity'].pubkey, + 'arcs': list(), + 'text': certified['identity'].uid, + 'tooltip': certified['identity'].pubkey, + 'status': node_status, + 'connected': [identity.pubkey] + } + # display validity status + if (time.time() - certified['cert_time']) > self.ARC_STATUS_STRONG_time: + arc_status = ARC_STATUS_WEAK + else: + arc_status = ARC_STATUS_STRONG + arc = { + 'id': certified['identity'].pubkey, + 'status': arc_status, + 'tooltip': QLocale.toString( + QLocale(), + QDateTime.fromTime_t(certified['cert_time'] + self.signature_validity).date(), + QLocale.dateFormat(QLocale(), QLocale.ShortFormat) + ), + 'cert_time': certified['cert_time'] + } - if max_validations > current_validations > 0: - if self.app.preferences['expert_mode']: - arc['validation_text'] = "{0}/{1}".format(current_validations, - max_validations) - else: - validation = current_validations / max_validations * 100 - validation = 100 if validation > 100 else validation - arc['validation_text'] = "{0} %".format(QLocale().toString(float(validation), 'f', 0)) - else: - arc['validation_text'] = None + if certified['block_number']: + current_validations = self.community.network.latest_block_number - certified['block_number'] + else: + current_validations = 0 + members_pubkeys = yield from self.community.members_pubkeys() + max_validations = self.community.network.fork_window(members_pubkeys) + 1 + + if max_validations > current_validations > 0: + if self.app.preferences['expert_mode']: + arc['validation_text'] = "{0}/{1}".format(current_validations, + max_validations) + else: + validation = current_validations / max_validations * 100 + validation = 100 if validation > 100 else validation + arc['validation_text'] = "{0} %".format(QLocale().toString(float(validation), 'f', 0)) + else: + arc['validation_text'] = None - # replace old arc if this one is more recent - new_arc = True - index = 0 - for a in self._graph[identity.pubkey]['arcs']: - # if same arc already exists... - if a['id'] == arc['id']: - # if arc more recent, dont keep old one... - if arc['cert_time'] >= a['cert_time']: - self._graph[identity.pubkey]['arcs'][index] = arc - new_arc = False - index += 1 + # replace old arc if this one is more recent + new_arc = True + index = 0 + for a in self._graph[identity.pubkey]['arcs']: + # if same arc already exists... + if a['id'] == arc['id']: + # if arc more recent, dont keep old one... + if arc['cert_time'] >= a['cert_time']: + self._graph[identity.pubkey]['arcs'][index] = arc + new_arc = False + index += 1 - # Â if arc not in graph... - if new_arc: - # add arc in graph - self._graph[identity.pubkey]['arcs'].append(arc) - # if certified node not in identity nodes - if certified['identity'].pubkey not in tuple(self._graph[identity.pubkey]['connected']): - # add certified node to identity node - self._graph[identity.pubkey]['connected'].append(certified['identity'].pubkey) + # Â if arc not in graph... + if new_arc: + # add arc in graph + self._graph[identity.pubkey]['arcs'].append(arc) + # if certified node not in identity nodes + if certified['identity'].pubkey not in tuple(self._graph[identity.pubkey]['connected']): + # add certified node to identity node + self._graph[identity.pubkey]['connected'].append(certified['identity'].pubkey) + except NoPeerAvailable as e: + logging.debug(str(e)) def add_identity(self, identity, status=None, arcs=None, connected=None): """ diff --git a/src/cutecoin/core/net/api/bma/access.py b/src/cutecoin/core/net/api/bma/access.py index dd431368..8700fc1f 100644 --- a/src/cutecoin/core/net/api/bma/access.py +++ b/src/cutecoin/core/net/api/bma/access.py @@ -152,26 +152,25 @@ class BmaAccess(QObject): need_reload = data[0] json_data = data[1] - if need_reload: - nodes = self._network.synced_nodes - if len(nodes) > 0: - tries = 0 - while tries < 3: - node = random.choice(nodes) - conn_handler = node.endpoint.conn_handler() - req = request(conn_handler, **req_args) - try: - json_data = yield from req.get(**get_args) - self._update_cache(request, req_args, get_args, json_data) - return json_data - except ValueError as e: - if '404' in str(e) or '400' in str(e): - raise - tries += 1 - except ClientError: - tries += 1 - else: - raise NoPeerAvailable("", nodes) + nodes = self._network.synced_nodes + if need_reload and len(nodes) > 0: + tries = 0 + while tries < 3: + node = random.choice(nodes) + conn_handler = node.endpoint.conn_handler() + req = request(conn_handler, **req_args) + try: + json_data = yield from req.get(**get_args) + self._update_cache(request, req_args, get_args, json_data) + return json_data + except ValueError as e: + if '404' in str(e) or '400' in str(e): + raise + tries += 1 + except ClientError: + tries += 1 + if len(nodes) == 0 or json_data is None: + raise NoPeerAvailable("", len(nodes)) return json_data def simple_request(self, request, req_args={}, get_args={}): @@ -216,5 +215,5 @@ class BmaAccess(QObject): reply = yield from req.post(**post_args) replies.append(reply) else: - raise NoPeerAvailable("", nodes) + raise NoPeerAvailable("", len(nodes)) return tuple(replies) diff --git a/src/cutecoin/core/registry/identity.py b/src/cutecoin/core/registry/identity.py index 8dedf2ad..aa651d3a 100644 --- a/src/cutecoin/core/registry/identity.py +++ b/src/cutecoin/core/registry/identity.py @@ -136,6 +136,10 @@ class Identity(QObject): except ValueError as e: if '404' in str(e) or '400' in str(e): raise MembershipNotFoundError(self.pubkey, community.name) + except NoPeerAvailable as e: + logging.debug(str(e)) + raise MembershipNotFoundError(self.pubkey, community.name) + @asyncio.coroutine def get_expiration_date(self, community): @@ -184,6 +188,9 @@ class Identity(QObject): except ValueError as e: if '404' in str(e) or '400' in str(e): raise MembershipNotFoundError(self.pubkey, community.name) + except NoPeerAvailable as e: + logging.debug(str(e)) + raise MembershipNotFoundError(self.pubkey, community.name) @asyncio.coroutine def published_uid(self, community): @@ -204,6 +211,8 @@ class Identity(QObject): person_uid = uid_data["uid"] if person_uid == self.uid: return True + except NoPeerAvailable as e: + logging.debug(str(e)) return False @asyncio.coroutine @@ -223,6 +232,8 @@ class Identity(QObject): pass else: raise + except NoPeerAvailable as e: + logging.debug(str(e)) return False @asyncio.coroutine @@ -236,7 +247,8 @@ class Identity(QObject): """ certifiers = list() try: - data = yield from community.bma_access.future_request(bma.wot.CertifiersOf, {'search': self.pubkey}) + data = yield from community.bma_access.future_request(bma.wot.CertifiersOf, + {'search': self.pubkey}) for certifier_data in data['certifications']: certifier = {} @@ -269,6 +281,8 @@ class Identity(QObject): certifiers.append(certifier) except ValueError as e: logging.debug("Lookup error : {0}".format(str(e))) + except NoPeerAvailable as e: + logging.debug(str(e)) return certifiers @asyncio.coroutine @@ -329,6 +343,8 @@ class Identity(QObject): except ValueError as e: if '404' in str(e): logging.debug('bma.wot.Lookup request error') + except NoPeerAvailable as e: + logging.debug(str(e)) return certified_list @asyncio.coroutine diff --git a/src/cutecoin/core/txhistory.py b/src/cutecoin/core/txhistory.py index d7f2a958..67c65e95 100644 --- a/src/cutecoin/core/txhistory.py +++ b/src/cutecoin/core/txhistory.py @@ -4,7 +4,7 @@ import hashlib from .transfer import Transfer from ucoinpy.documents.transaction import InputSource, OutputSource from ucoinpy.documents.block import Block -from ..tools.exceptions import LookupFailureError +from ..tools.exceptions import LookupFailureError, NoPeerAvailable from ucoinpy.api import bma @@ -214,61 +214,66 @@ class TxHistory(): :param cutecoin.core.Community community: The community :param list received_list: List of transactions received """ - current_block = yield from community.bma_access.future_request(bma.blockchain.Block, - req_args={'number': community.network.latest_block_number}) - members_pubkeys = yield from community.members_pubkeys() - # We look for the first block to parse, depending on awaiting and validating transfers and ud... - blocks = [tx.metadata['block'] for tx in self._transfers - if tx.state in (Transfer.AWAITING, Transfer.VALIDATING)] +\ - [ud['block_number'] for ud in self._dividends - if ud['state'] in (Transfer.AWAITING, Transfer.VALIDATING)] +\ - [max(0, self.latest_block - community.network.fork_window(members_pubkeys))] - parsed_block = min(set(blocks)) - logging.debug("Refresh from : {0} to {1}".format(self.latest_block, current_block['number'])) - dividends = yield from self.request_dividends(community, parsed_block) - with_tx_data = yield from community.bma_access.future_request(bma.blockchain.TX) - blocks_with_tx = with_tx_data['result']['blocks'] - new_transfers = [] - new_dividends = [] - # Lets look if transactions took too long to be validated - awaiting = [t for t in self._transfers - if t.state == Transfer.AWAITING] - while parsed_block <= current_block['number']: - udid = 0 - for d in [ud for ud in dividends if ud['block_number'] == parsed_block]: - state = yield from TxHistory._validation_state(community, d['block_number'], current_block) - - if d['block_number'] not in [ud['block_number'] for ud in self._dividends]: - d['id'] = udid - d['state'] = state - new_dividends.append(d) - udid += 1 - else: - known_dividend = [ud for ud in self._dividends - if ud['block_number'] == d['block_number']][0] - known_dividend['state'] = state - - # We parse only blocks with transactions - if parsed_block in blocks_with_tx: - transfers = yield from self._parse_block(community, parsed_block, - received_list, current_block, - udid + len(new_transfers)) - new_transfers += transfers - - self.wallet.refresh_progressed.emit(parsed_block, current_block['number'], self.wallet.pubkey) - parsed_block += 1 - - if current_block['number'] > self.latest_block: - self.available_sources = yield from self.wallet.future_sources(community) - if self._stop_coroutines: - return - self.latest_block = current_block['number'] - - parameters = yield from community.parameters() - for transfer in awaiting: - transfer.check_refused(current_block['medianTime'], - parameters['avgGenTime'], - parameters['medianTimeBlocks']) + try: + current_block = yield from community.bma_access.future_request(bma.blockchain.Block, + req_args={'number': community.network.latest_block_number}) + members_pubkeys = yield from community.members_pubkeys() + # We look for the first block to parse, depending on awaiting and validating transfers and ud... + blocks = [tx.metadata['block'] for tx in self._transfers + if tx.state in (Transfer.AWAITING, Transfer.VALIDATING)] +\ + [ud['block_number'] for ud in self._dividends + if ud['state'] in (Transfer.AWAITING, Transfer.VALIDATING)] +\ + [max(0, self.latest_block - community.network.fork_window(members_pubkeys))] + parsed_block = min(set(blocks)) + logging.debug("Refresh from : {0} to {1}".format(self.latest_block, current_block['number'])) + dividends = yield from self.request_dividends(community, parsed_block) + with_tx_data = yield from community.bma_access.future_request(bma.blockchain.TX) + blocks_with_tx = with_tx_data['result']['blocks'] + new_transfers = [] + new_dividends = [] + # Lets look if transactions took too long to be validated + awaiting = [t for t in self._transfers + if t.state == Transfer.AWAITING] + while parsed_block <= current_block['number']: + udid = 0 + for d in [ud for ud in dividends if ud['block_number'] == parsed_block]: + state = yield from TxHistory._validation_state(community, d['block_number'], current_block) + + if d['block_number'] not in [ud['block_number'] for ud in self._dividends]: + d['id'] = udid + d['state'] = state + new_dividends.append(d) + udid += 1 + else: + known_dividend = [ud for ud in self._dividends + if ud['block_number'] == d['block_number']][0] + known_dividend['state'] = state + + # We parse only blocks with transactions + if parsed_block in blocks_with_tx: + transfers = yield from self._parse_block(community, parsed_block, + received_list, current_block, + udid + len(new_transfers)) + new_transfers += transfers + + self.wallet.refresh_progressed.emit(parsed_block, current_block['number'], self.wallet.pubkey) + parsed_block += 1 + + if current_block['number'] > self.latest_block: + self.available_sources = yield from self.wallet.future_sources(community) + if self._stop_coroutines: + return + self.latest_block = current_block['number'] + + parameters = yield from community.parameters() + for transfer in awaiting: + transfer.check_refused(current_block['medianTime'], + parameters['avgGenTime'], + parameters['medianTimeBlocks']) + except NoPeerAvailable as e: + logging.debug(str(e)) + self.wallet.refresh_finished.emit([]) + return self._transfers = self._transfers + new_transfers self._dividends = self._dividends + new_dividends diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 4c81da5f..b06d95f7 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -272,21 +272,6 @@ class Wallet(QObject): logging.debug("Transaction : {0}".format(tx.signed_raw())) return (yield from transfer.send(tx, community)) - @asyncio.coroutine - def future_sources(self, community): - """ - Get available sources in a given community - - :param cutecoin.core.community.Community community: The community where we want available sources - :return: List of InputSource ucoinpy objects - """ - data = yield from community.bma_access.future_request(bma.tx.Sources, - req_args={'pubkey': self.pubkey}) - tx = [] - for s in data['sources']: - tx.append(InputSource.from_bma(s)) - return tx - @asyncio.coroutine def sources(self, community): """ @@ -295,11 +280,14 @@ class Wallet(QObject): :param cutecoin.core.community.Community community: The community where we want available sources :return: List of InputSource ucoinpy objects """ - data = yield from community.bma_access.future_request(bma.tx.Sources, - req_args={'pubkey': self.pubkey}) tx = [] - for s in data['sources']: - tx.append(InputSource.from_bma(s)) + try: + data = yield from community.bma_access.future_request(bma.tx.Sources, + req_args={'pubkey': self.pubkey}) + for s in data['sources']: + tx.append(InputSource.from_bma(s)) + except NoPeerAvailable as e: + logging.debug(str(e)) return tx def transfers(self, community): diff --git a/src/cutecoin/gui/certification.py b/src/cutecoin/gui/certification.py index 01b8d1ab..0df35848 100644 --- a/src/cutecoin/gui/certification.py +++ b/src/cutecoin/gui/certification.py @@ -9,6 +9,7 @@ from ..gen_resources.certification_uic import Ui_CertificationDialog from . import toast from .dialogs import QAsyncMessageBox from ..tools.decorators import asyncify +from ..tools.exceptions import NoPeerAvailable import asyncio import logging @@ -89,6 +90,10 @@ class CertificationDialog(QDialog, Ui_CertificationDialog): except ValueError as e: if '404' in str(e): block_0 = None + except NoPeerAvailable as e: + logging.debug(str(e)) + block_0 = None + if is_member or not block_0: self.button_box.button(QDialogButtonBox.Ok).setEnabled(True) self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok")) diff --git a/src/cutecoin/gui/community_tile.py b/src/cutecoin/gui/community_tile.py index 5feb2b39..4d6c0f0c 100644 --- a/src/cutecoin/gui/community_tile.py +++ b/src/cutecoin/gui/community_tile.py @@ -6,6 +6,7 @@ from PyQt5.QtWidgets import QFrame, QLabel, QVBoxLayout, QLayout, QPushButton from PyQt5.QtGui import QPalette from PyQt5.QtCore import QEvent, QSize, pyqtSignal from ..tools.decorators import asyncify +from ..tools.exceptions import NoPeerAvailable import asyncio from .busy import Busy @@ -34,40 +35,52 @@ class CommunityTile(QFrame): def refresh(self): self.busy.show() self.setFixedSize(QSize(150, 150)) - current_block = yield from self.community.get_block(self.community.network.latest_block_number) - members_pubkeys = yield from self.community.members_pubkeys() - amount = yield from self.app.current_account.amount(self.community) - localized_amount = yield from self.app.current_account.current_ref(amount, - self.community, self.app).localized(units=True, - international_system=self.app.preferences['international_system_of_units']) - if current_block['monetaryMass']: - localized_monetary_mass = yield from self.app.current_account.current_ref(current_block['monetaryMass'], - self.community, self.app).localized(units=True, - international_system=self.app.preferences['international_system_of_units']) - else: - localized_monetary_mass = "" - status = self.tr("Member") if self.app.current_account.pubkey in members_pubkeys \ - else self.tr("Non-Member") - description = """<html> - <body> - <p> - <span style=" font-size:16pt; font-weight:600;">{currency}</span> - </p> - <p>{nb_members} {members_label}</p> - <p><span style=" font-weight:600;">{monetary_mass_label}</span> : {monetary_mass}</p> - <p><span style=" font-weight:600;">{status_label}</span> : {status}</p> - <p><span style=" font-weight:600;">{balance_label}</span> : {balance}</p> - </body> - </html>""".format(currency=self.community.currency, - nb_members=len(members_pubkeys), - members_label=self.tr("members"), - monetary_mass_label=self.tr("Monetary mass"), - monetary_mass=localized_monetary_mass, - status_label=self.tr("Status"), - status=status, - balance_label=self.tr("Balance"), - balance=localized_amount) - self.text_label.setText(description) + try: + current_block = yield from self.community.get_block(self.community.network.latest_block_number) + members_pubkeys = yield from self.community.members_pubkeys() + amount = yield from self.app.current_account.amount(self.community) + localized_amount = yield from self.app.current_account.current_ref(amount, + self.community, self.app).localized(units=True, + international_system=self.app.preferences['international_system_of_units']) + if current_block['monetaryMass']: + localized_monetary_mass = yield from self.app.current_account.current_ref(current_block['monetaryMass'], + self.community, self.app).localized(units=True, + international_system=self.app.preferences['international_system_of_units']) + else: + localized_monetary_mass = "" + status = self.tr("Member") if self.app.current_account.pubkey in members_pubkeys \ + else self.tr("Non-Member") + description = """<html> + <body> + <p> + <span style=" font-size:16pt; font-weight:600;">{currency}</span> + </p> + <p>{nb_members} {members_label}</p> + <p><span style=" font-weight:600;">{monetary_mass_label}</span> : {monetary_mass}</p> + <p><span style=" font-weight:600;">{status_label}</span> : {status}</p> + <p><span style=" font-weight:600;">{balance_label}</span> : {balance}</p> + </body> + </html>""".format(currency=self.community.currency, + nb_members=len(members_pubkeys), + members_label=self.tr("members"), + monetary_mass_label=self.tr("Monetary mass"), + monetary_mass=localized_monetary_mass, + status_label=self.tr("Status"), + status=status, + balance_label=self.tr("Balance"), + balance=localized_amount) + self.text_label.setText(description) + except NoPeerAvailable: + description = """<html> + <body> + <p> + <span style=" font-size:16pt; font-weight:600;">{currency}</span> + </p> + <p>{message}</p> + </body> + </html>""".format(currency=self.community.currency, + message=self.tr("Not connected")) + self.text_label.setText(description) self.busy.hide() def mousePressEvent(self, event): diff --git a/src/cutecoin/gui/community_view.py b/src/cutecoin/gui/community_view.py index f2e41e8a..86186a84 100644 --- a/src/cutecoin/gui/community_view.py +++ b/src/cutecoin/gui/community_view.py @@ -182,13 +182,25 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): logging.debug("Refresh status") if self.community: text = self.tr(" Block {0}").format(self.community.network.latest_block_number) - - block = yield from self.community.get_block(self.community.network.latest_block_number) - text += " ( {0} )".format(QLocale.toString( - QLocale(), - QDateTime.fromTime_t(block['medianTime']), - QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat) - )) + try: + block = yield from self.community.get_block(self.community.network.latest_block_number) + text += " ( {0} )".format(QLocale.toString( + QLocale(), + QDateTime.fromTime_t(block['medianTime']), + QLocale.dateTimeFormat(QLocale(), QLocale.NarrowFormat) + )) + except NoPeerAvailable as e: + logging.debug(str(e)) + text += " ( ### ) " + + if len(self.community.network.synced_nodes) == 0: + self.button_membership.setEnabled(False) + self.button_certification.setEnabled(False) + self.button_send_money.setEnabled(False) + else: + self.button_membership.setEnabled(True) + self.button_certification.setEnabled(True) + self.button_send_money.setEnabled(True) if self.community.network.quality > 0.66: icon = '<img src=":/icons/connected" width="12" height="12"/>' @@ -196,15 +208,22 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): icon = '<img src=":/icons/weak_connect" width="12" height="12"/>' else: icon = '<img src=":/icons/disconnected" width="12" height="12"/>' + status_infotext = " - ".join([self.status_infotext[info] for info in self.status_info]) label_text = "{0}{1}".format(icon, text) if status_infotext != "": label_text += " - {0}".format(status_infotext) if self.app.preferences['expert_mode']: - members_pubkeys = yield from self.community.members_pubkeys() - label_text += self.tr(" - Median fork window : {0}")\ - .format(self.community.network.fork_window(members_pubkeys)) + try: + members_pubkeys = yield from self.community.members_pubkeys() + label_text += self.tr(" - Median fork window : {0}")\ + .format(self.community.network.fork_window(members_pubkeys)) + except NoPeerAvailable as e: + logging.debug(str(e)) + label_text += self.tr(" - Median fork window : {0}")\ + .format("#") + self.status_label.setText(label_text) @@ -227,7 +246,7 @@ class CommunityWidget(QWidget, Ui_CommunityWidget): logging.debug("Not a member") self.button_membership.setText(self.tr("Send membership demand")) self.button_membership.show() - if self.community.get_block(0) != bma.blockchain.Block.null_value: + if self.community.get_block(0) != None: self.button_certification.hide() else: logging.debug("UID not published") diff --git a/src/cutecoin/gui/identities_tab.py b/src/cutecoin/gui/identities_tab.py index 002da0fe..a9a3e5dc 100644 --- a/src/cutecoin/gui/identities_tab.py +++ b/src/cutecoin/gui/identities_tab.py @@ -19,6 +19,7 @@ from .certification import CertificationDialog import asyncio from ucoinpy.api import bma from ..core.registry import Identity +from ..tools.exceptions import NoPeerAvailable from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task @@ -219,21 +220,26 @@ class IdentitiesTabWidget(QWidget, Ui_IdentitiesTab): Search members of community and display found members """ if self.account and self.community: - self.busy.show() - self_identity = yield from self.account.identity(self.community) - account_connections = [] - certs_of = yield from self_identity.unique_valid_certifiers_of(self.app.identities_registry, self.community) - for p in certs_of: - account_connections.append(p['identity']) - certifiers_of = [p for p in account_connections] - certs_by = yield from self_identity.unique_valid_certified_by(self.app.identities_registry, self.community) - for p in certs_by: - account_connections.append(p['identity']) - certified_by = [p for p in account_connections - if p.pubkey not in [i.pubkey for i in certifiers_of]] - identities = certifiers_of + certified_by - self.refresh_identities(identities) - self.busy.hide() + try: + self.busy.show() + self_identity = yield from self.account.identity(self.community) + account_connections = [] + certs_of = yield from self_identity.unique_valid_certifiers_of(self.app.identities_registry, self.community) + for p in certs_of: + account_connections.append(p['identity']) + certifiers_of = [p for p in account_connections] + certs_by = yield from self_identity.unique_valid_certified_by(self.app.identities_registry, self.community) + for p in certs_by: + account_connections.append(p['identity']) + certified_by = [p for p in account_connections + if p.pubkey not in [i.pubkey for i in certifiers_of]] + identities = certifiers_of + certified_by + self.refresh_identities(identities) + except NoPeerAvailable: + pass + finally: + self.refresh_identities([]) + self.busy.hide() @once_at_a_time @asyncify diff --git a/src/cutecoin/gui/transactions_tab.py b/src/cutecoin/gui/transactions_tab.py index 64844bf9..cf6a431e 100644 --- a/src/cutecoin/gui/transactions_tab.py +++ b/src/cutecoin/gui/transactions_tab.py @@ -11,6 +11,7 @@ from .transfer import TransferMoneyDialog from .certification import CertificationDialog from ..core.wallet import Wallet from ..core.registry import Identity +from ..tools.exceptions import NoPeerAvailable from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task from .transfer import TransferMoneyDialog from . import toast @@ -81,19 +82,22 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): @asyncify @asyncio.coroutine def refresh_minimum_maximum(self): - block = yield from self.community.get_block(1) - minimum_datetime = QDateTime() - minimum_datetime.setTime_t(block['medianTime']) - minimum_datetime.setTime(QTime(0, 0)) - - self.date_from.setMinimumDateTime(minimum_datetime) - self.date_from.setDateTime(minimum_datetime) - self.date_from.setMaximumDateTime(QDateTime().currentDateTime()) - - self.date_to.setMinimumDateTime(minimum_datetime) - tomorrow_datetime = QDateTime().currentDateTime().addDays(1) - self.date_to.setDateTime(tomorrow_datetime) - self.date_to.setMaximumDateTime(tomorrow_datetime) + try: + block = yield from self.community.get_block(1) + minimum_datetime = QDateTime() + minimum_datetime.setTime_t(block['medianTime']) + minimum_datetime.setTime(QTime(0, 0)) + + self.date_from.setMinimumDateTime(minimum_datetime) + self.date_from.setDateTime(minimum_datetime) + self.date_from.setMaximumDateTime(QDateTime().currentDateTime()) + + self.date_to.setMinimumDateTime(minimum_datetime) + tomorrow_datetime = QDateTime().currentDateTime().addDays(1) + self.date_to.setDateTime(tomorrow_datetime) + self.date_to.setMaximumDateTime(tomorrow_datetime) + except NoPeerAvailable as e: + logging.debug(str(e)) def refresh(self): #TODO: Use resetmodel instead of destroy/create diff --git a/src/cutecoin/models/identities.py b/src/cutecoin/models/identities.py index b412c455..e970f0bd 100644 --- a/src/cutecoin/models/identities.py +++ b/src/cutecoin/models/identities.py @@ -132,8 +132,12 @@ class IdentitiesTableModel(QAbstractTableModel): for identity in identities: data = yield from self.identity_data(identity) self.identities_data.append(data) - parameters = yield from self.community.parameters() - self._sig_validity = parameters['sigValidity'] + try: + parameters = yield from self.community.parameters() + self._sig_validity = parameters['sigValidity'] + except NoPeerAvailable as e: + logging.debug(str(e)) + self._sig_validity = 0 self.endResetModel() def rowCount(self, parent): diff --git a/src/cutecoin/models/txhistory.py b/src/cutecoin/models/txhistory.py index 31cdc1d3..4d9dfe64 100644 --- a/src/cutecoin/models/txhistory.py +++ b/src/cutecoin/models/txhistory.py @@ -8,6 +8,7 @@ import datetime import logging import asyncio from ..core.transfer import Transfer +from ..tools.exceptions import NoPeerAvailable from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QSortFilterProxyModel, \ QDateTime, QLocale, QModelIndex @@ -300,8 +301,12 @@ class HistoryTableModel(QAbstractTableModel): data = yield from self.data_dividend(transfer) if data: self.transfers_data.append(data) - members_pubkeys = yield from self.community.members_pubkeys() - self._max_validations = self.community.network.fork_window(members_pubkeys) + 1 + try: + members_pubkeys = yield from self.community.members_pubkeys() + self._max_validations = self.community.network.fork_window(members_pubkeys) + 1 + except NoPeerAvailable as e: + logging.debug(str(e)) + self._max_validations = 0 self.endResetModel() def max_validations(self): diff --git a/src/cutecoin/tools/exceptions.py b/src/cutecoin/tools/exceptions.py index 8821d1c8..6044c9b6 100644 --- a/src/cutecoin/tools/exceptions.py +++ b/src/cutecoin/tools/exceptions.py @@ -154,13 +154,13 @@ class NoPeerAvailable(Error): Exception raised when a community doesn't have any peer available. """ - def __init__(self, currency, peers): + def __init__(self, currency, nbpeers): """ Constructor """ super() .__init__( "No peer answered in {0} community ({1} peers available)" - .format(currency, peers)) + .format(currency, nbpeers)) class InvalidNodeCurrency(Error): -- GitLab