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