diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 018f65f1e9ecb87ebee341551657ca7ef4dd4fab..12def58c8718065c6a9f3150e8b4acd3df31f1a0 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -85,8 +85,9 @@ class Community(object): self._cache.refresh() @classmethod - def create(cls, currency, peer): - community = cls(currency, [peer]) + def create(cls, node): + network = Network.create(node) + community = cls(node.currency, network) logging.debug("Creating community") return community diff --git a/src/cutecoin/core/net/network.py b/src/cutecoin/core/net/network.py index 665fe9d66a233de79e26cdaed7cd794e01a4c92c..68a41729cc2945590d25297ed418fe894e7a9002 100644 --- a/src/cutecoin/core/net/network.py +++ b/src/cutecoin/core/net/network.py @@ -42,23 +42,23 @@ class Network(QObject): logging.debug("Loading : {:}".format(data['pubkey'])) block_max = max([n.block for n in nodes]) for node in nodes: - node.check_sync(currency, block_max) + node.check_sync(block_max) return cls(currency, nodes) @classmethod - def create(cls, currency, node): + def create(cls, node): nodes = [node] - network = cls(currency, nodes) - nodes = network.crawling + network = cls(node.currency, nodes) + nodes = network.crawling() block_max = max([n.block for n in nodes]) for node in nodes: - node.check_sync(currency, block_max) + node.check_sync(block_max) network._nodes = nodes return network def jsonify(self): data = [] - for node in self.nodes: + for node in self._nodes: data.append(node.jsonify()) return data @@ -105,13 +105,13 @@ class Network(QObject): logging.debug("Peering : next to read : {0} : {1}".format(n.pubkey, (n.pubkey not in traversed_pubkeys))) if n.pubkey not in traversed_pubkeys: - n.peering_traversal(self.currency, nodes, + n.peering_traversal(nodes, traversed_pubkeys, interval) time.sleep(interval) block_max = max([n.block for n in nodes]) for node in [n for n in nodes if n.state == Node.ONLINE]: - node.check_sync(self.currency, block_max) + node.check_sync(block_max) #TODO: Offline nodes for too long have to be removed #TODO: Corrupted nodes should maybe be removed faster ? diff --git a/src/cutecoin/core/net/node.py b/src/cutecoin/core/net/node.py index 448e14a8ca632dcad4021860a75a386c8a267e34..5c84c5f002f09d940537573170912d7c4fc8d8da 100644 --- a/src/cutecoin/core/net/node.py +++ b/src/cutecoin/core/net/node.py @@ -6,7 +6,9 @@ Created on 21 févr. 2015 from ucoinpy.documents.peer import Peer, BMAEndpoint, Endpoint from ucoinpy.api import bma +from ucoinpy.api.bma import ConnectionHandler from requests.exceptions import RequestException +from ...tools.exceptions import InvalidNodeCurrency import logging import time @@ -25,7 +27,7 @@ class Node(QObject): changed = pyqtSignal() - def __init__(self, endpoints, pubkey, block, state): + def __init__(self, currency, endpoints, pubkey, block, state): ''' Constructor ''' @@ -35,11 +37,31 @@ class Node(QObject): self._block = block self._state = state self._neighbours = [] + self._currency = currency + + @classmethod + def from_address(cls, currency, address, port): + peer_data = bma.network.Peering(ConnectionHandler(address, port)).get() + + peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'], + peer_data['signature'])) + + if currency is not None: + if peer.currency != currency: + raise InvalidNodeCurrency(peer.currency, currency) + + node = cls(peer.currency, peer.endpoints, peer.pubkey, 0, Node.ONLINE) + node.refresh_state() + return node @classmethod def from_peer(cls, currency, peer): - node = cls(peer.endpoints, "", 0, Node.ONLINE) - node.refresh_state(currency) + if currency is not None: + if peer.currency != currency: + raise InvalidNodeCurrency(peer.currency, currency) + + node = cls(peer.currency, peer.endpoints, "", 0, Node.ONLINE) + node.refresh_state() return node @classmethod @@ -48,12 +70,15 @@ class Node(QObject): for endpoint_data in data['endpoints']: endpoints.append(Endpoint.from_inline(endpoint_data)) - node = cls(endpoints, "", 0, Node.ONLINE) - node.refresh_state(currency) + currency = data['currency'] + + node = cls(currency, endpoints, "", 0, Node.ONLINE) + node.refresh_state() return node def jsonify(self): - data = {'pubkey': self._pubkey} + data = {'pubkey': self._pubkey, + 'currency': self._currency} endpoints = [] for e in self._endpoints: endpoints.append(e.inline()) @@ -76,17 +101,21 @@ class Node(QObject): def state(self): return self._state + @property + def currency(self): + return self._currency + @property def neighbours(self): return self._neighbours - def check_sync(self, currency, block): + def check_sync(self, block): if self._block < block: self._state = Node.DESYNCED else: self._state = Node.ONLINE - def refresh_state(self, currency): + def refresh_state(self): emit_change = False try: informations = bma.network.Peering(self.endpoint.conn_handler()).get() @@ -108,7 +137,7 @@ class Node(QObject): self._state = Node.OFFLINE emit_change = True - if node_currency != currency: + if node_currency != self._currency: self.state = Node.CORRUPTED emit_change = True @@ -133,26 +162,27 @@ class Node(QObject): if emit_change: self.changed.emit() - def peering_traversal(self, currency, found_nodes, + def peering_traversal(self, found_nodes, traversed_pubkeys, interval): logging.debug("Read {0} peering".format(self.pubkey)) traversed_pubkeys.append(self.pubkey) - self.refresh_state(currency) + self.refresh_state() if self.pubkey not in [n.pubkey for n in found_nodes]: found_nodes.append(self) try: + logging.debug(self.neighbours) for n in self.neighbours: - e = next((e for e in self._endpoints if type(e) is BMAEndpoint)) - peering = bma.network.Peering(self.endpoint.conn_handler()).get() + e = next(e for e in n if type(e) is BMAEndpoint) + peering = bma.network.Peering(e.conn_handler()).get() peer = Peer.from_signed_raw("{0}{1}\n".format(peering['raw'], peering['signature'])) - node = Node.from_peer(currency, peer) + node = Node.from_peer(self._currency, peer) logging.debug(traversed_pubkeys) logging.debug("Traversing : next to read : {0} : {1}".format(node.pubkey, (node.pubkey not in traversed_pubkeys))) if node.pubkey not in traversed_pubkeys: - node.peering_traversal(currency, found_nodes, + node.peering_traversal(found_nodes, traversed_pubkeys, interval) time.sleep(interval) except RequestException as e: diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index 3016af98064ef644b08b979416c88a719e659c38..ade37b2388e290639e13f6c3872be4143871d7bd 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -57,7 +57,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): model = self.table_community_members.model() if index.row() < model.rowCount(): source_index = model.mapToSource(index) - pubkey_col = model.sourceModel().columns.index('Pubkey') + pubkey_col = model.sourceModel().columns_ids.index('pubkey') pubkey_index = model.sourceModel().index(source_index.row(), pubkey_col) pubkey = model.sourceModel().data(pubkey_index, Qt.DisplayRole) diff --git a/src/cutecoin/gui/mainwindow.py b/src/cutecoin/gui/mainwindow.py index 90d7c29db88cc8dfa782437527ec428aca9dbec9..0f49b9f9ad5c80b82d21ceb3da0042ff8be5f9d4 100644 --- a/src/cutecoin/gui/mainwindow.py +++ b/src/cutecoin/gui/mainwindow.py @@ -179,7 +179,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): def open_configure_account_dialog(self): dialog = ProcessConfigureAccount(self.app, self.app.current_account) dialog.accepted.connect(self.refresh) - dialog.exec_() + result = dialog.exec_() + if result == QDialog.Accepted: + self.action_change_account(self.app.current_account.name) def open_about_popup(self): """ diff --git a/src/cutecoin/gui/process_cfg_account.py b/src/cutecoin/gui/process_cfg_account.py index d61e3f438717642f7cbb130169fa2d1977b330cb..795d1ec265fd48a1529f9739f5cadbe88b712884 100644 --- a/src/cutecoin/gui/process_cfg_account.py +++ b/src/cutecoin/gui/process_cfg_account.py @@ -121,16 +121,11 @@ class StepPageCommunities(Step): nb_wallets = self.config_dialog.spinbox_wallets.value() self.config_dialog.account.set_walletpool_size(nb_wallets, password) + self.config_dialog.app.add_account(self.config_dialog.account) if len(self.config_dialog.app.accounts) == 1: self.config_dialog.app.default_account = self.config_dialog.account.name - - try: - self.config_dialog.app.add_account(self.config_dialog.account) - except KeyAlreadyUsed as e: - QMessageBox.critical(self, "Error", - str(e), QMessageBox.Ok) - return self.config_dialog.app.save(self.config_dialog.account) + self.config_dialog.app.current_account = self.config_dialog.account def display_page(self): logging.debug("Communities DISPLAY") diff --git a/src/cutecoin/gui/process_cfg_community.py b/src/cutecoin/gui/process_cfg_community.py index 29a6e72b06c92c651ec387862188818c4021fa1e..f0356966c60d04181115f5a54e136b31b0abe2c6 100644 --- a/src/cutecoin/gui/process_cfg_community.py +++ b/src/cutecoin/gui/process_cfg_community.py @@ -17,6 +17,7 @@ from ..gen_resources.community_cfg_uic import Ui_CommunityConfigurationDialog from ..models.peering import PeeringTreeModel from ..core.community import Community from ..core.person import Person +from ..core.net.node import Node from ..tools.exceptions import PersonNotFoundError, NoPeerAvailable @@ -33,6 +34,7 @@ class StepPageInit(Step): ''' def __init__(self, config_dialog): super().__init__(config_dialog) + self.node = None logging.debug("Init") def is_valid(self): @@ -40,38 +42,21 @@ class StepPageInit(Step): port = self.config_dialog.spinbox_port.value() logging.debug("Is valid ? ") try: - peer_data = bma.network.Peering(ConnectionHandler(server, port)) - peer_data.get()['raw'] - except: - QMessageBox.critical(self.config_dialog, "Server error", - "Cannot get node peering") - return False + self.node = Node.from_address(None, server, port) + except Exception as e: + QMessageBox.critical(self.config_dialog, ":(", + str(e), + QMessageBox.Ok) + return True def process_next(self): ''' We create the community ''' - server = self.config_dialog.lineedit_server.text() - port = self.config_dialog.spinbox_port.value() account = self.config_dialog.account logging.debug("Account : {0}".format(account)) - try: - peering = bma.network.Peering(ConnectionHandler(server, port)) - peer_data = peering.get() - peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'], - peer_data['signature'])) - currency = peer.currency - self.config_dialog.community = Community.create(currency, peer) - except NoPeerAvailable: - QMessageBox.critical(self.config_dialog, "Server Error", - "Cannot join any peer in this community.") - raise - except requests.exceptions.RequestException as e: - QMessageBox.critical(self.config_dialog, ":(", - str(e), - QMessageBox.Ok) - raise + self.config_dialog.community = Community.create(self.node) def display_page(self): self.config_dialog.button_previous.setEnabled(False) @@ -168,19 +153,13 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): ''' server = self.lineedit_server.text() port = self.spinbox_port.value() - try: - peer_data = bma.network.Peering(ConnectionHandler(server, port)).get() - peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'], - peer_data['signature'])) - if peer.currency == self.community.currency: - self.community.add_peer(peer) - else: - QMessageBox.critical(self, "Error", - "This peer doesn't use this community currency.") - except requests.exceptions.RequestException as e: - QMessageBox.critical(self, "Server error", - "Cannot get node peering") + try: + node = Node.from_address(self.community.currency, server, port) + self.community.add_node(node) + except Exception as e: + QMessageBox.critical(self, "Error", + str(e)) self.tree_peers.setModel(PeeringTreeModel(self.community)) def showContextMenu(self, point): diff --git a/src/cutecoin/tools/exceptions.py b/src/cutecoin/tools/exceptions.py index d063899b1812883197e96ceec3efaad1cad6d8ed..f394b397109d777550893881fd698817120ec199 100644 --- a/src/cutecoin/tools/exceptions.py +++ b/src/cutecoin/tools/exceptions.py @@ -163,6 +163,19 @@ class NoPeerAvailable(Error): .format(currency, peers)) +class InvalidNodeCurrency(Error): + ''' + Exception raised when a node doesn't use the intended currency + ''' + def __init__(self, currency, node_currency): + ''' + Constructor + ''' + super() .__init__( + "Node is working for {0} currency, but should be {1}" + .format(node_currency, currency)) + + class ContactAlreadyExists(Error): ''' Exception raised when a community doesn't have any