async def from_address(cls, currency, address, port): """ Factory method to get a node from a given address :param str currency: The node currency. None if we don't know\ the currency it should have, for example if its the first one we add :param str address: The node address :param int port: The node port :return: A new node :rtype: sakia.core.net.Node """ peer_data = await 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, "", peer.pubkey, None, Node.ONLINE, time.time(), {'root': "", 'leaves': []}, "", "", 0) logging.debug("Node from address : {:}".format(str(node))) return node
def peering_traversal(self, knew_pubkeys, found_nodes, traversed_pubkeys, interval, continue_crawling): logging.debug("Read {0} peering".format(self.pubkey)) traversed_pubkeys.append(self.pubkey) self.refresh_state() if self.pubkey not in [n.pubkey for n in found_nodes]: # if node is corrupted remove it if self.state != Node.CORRUPTED: logging.debug("Found : {0} node".format(self.pubkey)) found_nodes.append(self) logging.debug(self.neighbours) for n in self.neighbours: try: e = next(e for e in n if type(e) is BMAEndpoint) peering = bma.network.Peering(e.conn_handler()).get() except: continue peer = Peer.from_signed_raw("{0}{1}\n".format( peering['raw'], peering['signature'])) if peer.pubkey not in traversed_pubkeys and \ peer.pubkey not in knew_pubkeys and continue_crawling(): 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))) node.peering_traversal(knew_pubkeys, found_nodes, traversed_pubkeys, interval, continue_crawling) time.sleep(interval)
def peering_traversal(self, knew_pubkeys, found_nodes, traversed_pubkeys, interval, continue_crawling): logging.debug("Read {0} peering".format(self.pubkey)) traversed_pubkeys.append(self.pubkey) self.refresh_state() if self.pubkey not in [n.pubkey for n in found_nodes]: # if node is corrupted remove it if self.state != Node.CORRUPTED: logging.debug("Found : {0} node".format(self.pubkey)) found_nodes.append(self) logging.debug(self.neighbours) for n in self.neighbours: try: e = next(e for e in n if type(e) is BMAEndpoint) peering = bma.network.Peering(e.conn_handler()).get() except: continue peer = Peer.from_signed_raw("{0}{1}\n".format(peering['raw'], peering['signature'])) if peer.pubkey not in traversed_pubkeys and \ peer.pubkey not in knew_pubkeys and continue_crawling(): 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))) node.peering_traversal(knew_pubkeys, found_nodes, traversed_pubkeys, interval, continue_crawling) time.sleep(interval)
def refresh_peer_data(self, peer_data): if "raw" in peer_data: try: str_doc = "{0}{1}\n".format(peer_data['raw'], peer_data['signature']) peer_doc = Peer.from_signed_raw(str_doc) pubkey = peer_data['pubkey'] self.neighbour_found.emit(peer_doc, pubkey) except MalformedDocumentError as e: logging.debug(str(e)) else: logging.debug("Incorrect leaf reply")
async def refresh_informations(self): """ Refresh basic information (pubkey and currency) """ conn_handler = self.endpoint.conn_handler() try: peering_data = await bma.network.Peering(conn_handler).get() node_pubkey = peering_data["pubkey"] node_currency = peering_data["currency"] self.state = Node.ONLINE if peering_data['raw'] != self.peer.raw(): peer = Peer.from_signed_raw("{0}{1}\n".format(peering_data['raw'], peering_data['signature'])) if peer.blockid.number > peer.blockid.number: self.peer = Peer.from_signed_raw("{0}{1}\n".format(peering_data['raw'], peering_data['signature'])) if node_pubkey != self.pubkey: self._pubkey = node_pubkey self.identity_changed.emit() if node_currency != self.currency: self.state = Node.CORRUPTED logging.debug("Change : new state corrupted") self.changed.emit() except ValueError as e: logging.debug("Error in peering reply : {0}".format(str(e))) self.state = Node.OFFLINE self.changed.emit() except (ClientError, gaierror, TimeoutError, DisconnectedError) as e: logging.debug("{0} : {1}".format(type(e).__name__, self.pubkey[:5])) self.state = Node.OFFLINE except jsonschema.ValidationError as e: logging.debug(str(e)) logging.debug("Validation error : {0}".format(self.pubkey[:5])) self.state = Node.CORRUPTED
def refresh_peers(self): """ Refresh the list of peers knew by this node """ conn_handler = self.endpoint.conn_handler() try: peers_data = yield from bma.network.peering.Peers(conn_handler).get(leaves='true') self.state = Node.ONLINE if peers_data['root'] != self._last_merkle['root']: leaves = [leaf for leaf in peers_data['leaves'] if leaf not in self._last_merkle['leaves']] for leaf_hash in leaves: try: leaf_data = yield from bma.network.peering.Peers(conn_handler).get(leaf=leaf_hash) if "raw" in leaf_data['leaf']['value']: str_doc = "{0}{1}\n".format(leaf_data['leaf']['value']['raw'], leaf_data['leaf']['value']['signature']) peer_doc = Peer.from_signed_raw(str_doc) pubkey = leaf_data['leaf']['value']['pubkey'] self.neighbour_found.emit(peer_doc, pubkey) else: logging.debug("Incorrect leaf reply") except (AttributeError, ValueError) as e: logging.debug("{pubkey} : Incorrect peer data in {leaf}".format(pubkey=self.pubkey[:5], leaf=leaf_hash)) self.state = Node.OFFLINE self.changed.emit() except (ClientError, gaierror, TimeoutError, DisconnectedError) as e: logging.debug("{0} : {1}".format(type(e).__name__, self.pubkey)) self.state = Node.OFFLINE except jsonschema.ValidationError: logging.debug("Validation error : {0}".format(self.pubkey)) self.state = Node.CORRUPTED self._last_merkle = {'root' : peers_data['root'], 'leaves': peers_data['leaves']} except ValueError as e: logging.debug("Error in peers reply") self.state = Node.OFFLINE self.changed.emit() except (ClientError, gaierror, TimeoutError, DisconnectedError) as e: logging.debug("{0} : {1}".format(type(e).__name__, self.pubkey)) self.state = Node.OFFLINE except jsonschema.ValidationError: logging.debug("Validation error : {0}".format(self.pubkey)) self.state = Node.CORRUPTED
def from_address(cls, currency, address, port): ''' Factory method to get a node from a given address :param str currency: The node currency. None if we don't know\ the currency it should have, for example if its the first one we add :param str address: The node address :param int port: The node 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, time.time(), "", "") logging.debug("Node from address : {:}".format(str(node))) return node
def setUp(self): self.setUpQuamash() QLocale.setDefault(QLocale("en_GB")) self.identities_registry = IdentitiesRegistry() self.application = Application(self.qapplication, self.lp, self.identities_registry) self.application.preferences['notifications'] = False self.peer = Peer.from_signed_raw("""Version: 1 Type: Peer Currency: meta_brouzouf PublicKey: 8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU Block: 48698-000005E0F228038E4DDD4F6CA4ACB01EC88FBAF8 Endpoints: BASIC_MERKLED_API ucoin.inso.ovh 80 82o1sNCh1bLpUXU6nacbK48HBcA9Eu2sPkL1/3c2GtDPxBUZd2U2sb7DxwJ54n6ce9G0Oy7nd1hCxN3fS0oADw== """) self.node = Node(self.peer, "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", None, Node.ONLINE, time.time(), {}, "ucoin", "0.12.0", 0) self.network = Network.create(self.node) self.bma_access = BmaAccess.create(self.network) self.community = Community("test_currency", self.network, self.bma_access)
def from_json(cls, currency, data, file_version): """ Loads a node from json data :param str currency: the currency of the community :param dict data: the json data of the node :param NormalizedVersion file_version: the version of the file :return: A new node :rtype: Node """ endpoints = [] uid = "" pubkey = "" software = "" version = "" fork_window = 0 block = None last_change = time.time() state = Node.OFFLINE if 'uid' in data: uid = data['uid'] if 'pubkey' in data: pubkey = data['pubkey'] if 'last_change' in data: last_change = data['last_change'] if 'block' in data: block = data['block'] if 'state' in data: state = data['state'] if 'software' in data: software = data['software'] if 'version' in data: version = data['version'] if 'fork_window' in data: fork_window = data['fork_window'] if parse_version("0.11") <= file_version < parse_version("0.12dev1") : for endpoint_data in data['endpoints']: endpoints.append(Endpoint.from_inline(endpoint_data)) if currency in data: currency = data['currency'] peer = Peer("1", currency, pubkey, BlockId(0, Block.Empty_Hash), endpoints, "SOMEFAKESIGNATURE") else: peer = Peer.from_signed_raw(data['peer']) node = cls(peer, uid, pubkey, block, state, last_change, {'root': "", 'leaves': []}, software, version, fork_window) logging.debug("Node from json : {:}".format(str(node))) return node
def refresh_state(self): logging.debug("Refresh state") emit_change = False try: informations = bma.network.Peering(self.endpoint.conn_handler()).get() node_pubkey = informations["pubkey"] try: block = bma.blockchain.Current(self.endpoint.conn_handler()).get() block_number = block["number"] except ValueError as e: if '404' in str(e): block_number = 0 peers_data = bma.network.peering.Peers(self.endpoint.conn_handler()).get() neighbours = [] for p in peers_data: peer = Peer.from_signed_raw("{0}{1}\n".format(p['value']['raw'], p['value']['signature'])) neighbours.append(peer.endpoints) logging.debug("Found neighbours : {0}".format(len(neighbours))) node_currency = informations["currency"] node_uid = self._request_uid() implementation = bma.node.Summary(self.endpoint.conn_handler()).get() software = implementation["ucoin"]["software"] version = implementation["ucoin"]["version"] #If the nodes goes back online... if self.state in (Node.OFFLINE, Node.CORRUPTED): self.state = Node.ONLINE logging.debug("Change : new state online") emit_change = True except ConnectionError as e: logging.debug(str(e)) if self.state != Node.OFFLINE: self.state = Node.OFFLINE logging.debug("Change : new state offine") emit_change = True # Dirty hack to reload resolv.conf on linux if 'Connection aborted' in str(e) and 'gaierror' in str(e): logging.debug("Connection Aborted") if 'linux' in sys.platform: try: libc = ctypes.CDLL('libc.so.6') res_init = getattr(libc, '__res_init') res_init(None) except: logging.error('Error calling libc.__res_init') except RequestException as e: logging.debug(str(e)) if self.state != Node.OFFLINE: self.state = Node.OFFLINE logging.debug("Change : new state offine") emit_change = True # If not is offline, do not refresh last data if self.state != Node.OFFLINE: # If not changed its currency, consider it corrupted if node_currency != self._currency: self.state = Node.CORRUPTED logging.debug("Change : new state corrupted") emit_change = True else: if block_number != self.block: logging.debug("Change : new block {0} -> {1}".format(self.block, block_number)) self.block = block_number logging.debug("Changed block {0} -> {1}".format(self.block, block_number)) emit_change = True if node_pubkey != self._pubkey: logging.debug("Change : new pubkey {0} -> {1}".format(self._pubkey, node_pubkey)) self._pubkey = node_pubkey emit_change = True if node_uid != self._uid: logging.debug("Change : new uid") self._uid = node_uid emit_change = True if software != self._software: logging.debug("Change : new software") self._software = software emit_change = True if version != self._version: logging.debug("Change : new version") self._version = version emit_change = True logging.debug(neighbours) new_inlines = [e.inline() for n in neighbours for e in n] last_inlines = [e.inline() for n in self._neighbours for e in n] hash_new_neighbours = hash(tuple(frozenset(sorted(new_inlines)))) hash_last_neighbours = hash(tuple(frozenset(sorted(last_inlines)))) if hash_new_neighbours != hash_last_neighbours: self._neighbours = neighbours logging.debug("Change : new neighbours {0} -> {1}".format(last_inlines, new_inlines)) emit_change = True if emit_change: self.changed.emit()
def refresh_state(self): logging.debug("Refresh state") emit_change = False try: informations = bma.network.Peering( self.endpoint.conn_handler()).get() node_pubkey = informations["pubkey"] try: block = bma.blockchain.Current( self.endpoint.conn_handler()).get() block_number = block["number"] except ValueError as e: if '404' in str(e): block_number = 0 peers_data = bma.network.peering.Peers( self.endpoint.conn_handler()).get() neighbours = [] for p in peers_data: peer = Peer.from_signed_raw("{0}{1}\n".format( p['value']['raw'], p['value']['signature'])) neighbours.append(peer.endpoints) logging.debug("Found neighbours : {0}".format(len(neighbours))) node_currency = informations["currency"] node_uid = self._request_uid() implementation = bma.node.Summary( self.endpoint.conn_handler()).get() software = implementation["ucoin"]["software"] version = implementation["ucoin"]["version"] #If the nodes goes back online... if self.state in (Node.OFFLINE, Node.CORRUPTED): self.state = Node.ONLINE logging.debug("Change : new state online") emit_change = True except ConnectionError as e: logging.debug(str(e)) if self.state != Node.OFFLINE: self.state = Node.OFFLINE logging.debug("Change : new state offine") emit_change = True # Dirty hack to reload resolv.conf on linux if 'Connection aborted' in str(e) and 'gaierror' in str(e): logging.debug("Connection Aborted") if 'linux' in sys.platform: try: libc = ctypes.CDLL('libc.so.6') res_init = getattr(libc, '__res_init') res_init(None) except: logging.error('Error calling libc.__res_init') except RequestException as e: logging.debug(str(e)) if self.state != Node.OFFLINE: self.state = Node.OFFLINE logging.debug("Change : new state offine") emit_change = True # If not is offline, do not refresh last data if self.state != Node.OFFLINE: # If not changed its currency, consider it corrupted if node_currency != self._currency: self.state = Node.CORRUPTED logging.debug("Change : new state corrupted") emit_change = True else: if block_number != self.block: logging.debug("Change : new block {0} -> {1}".format( self.block, block_number)) self.block = block_number logging.debug("Changed block {0} -> {1}".format( self.block, block_number)) emit_change = True if node_pubkey != self._pubkey: logging.debug("Change : new pubkey {0} -> {1}".format( self._pubkey, node_pubkey)) self._pubkey = node_pubkey emit_change = True if node_uid != self._uid: logging.debug("Change : new uid") self._uid = node_uid emit_change = True if software != self._software: logging.debug("Change : new software") self._software = software emit_change = True if version != self._version: logging.debug("Change : new version") self._version = version emit_change = True logging.debug(neighbours) new_inlines = [e.inline() for n in neighbours for e in n] last_inlines = [ e.inline() for n in self._neighbours for e in n ] hash_new_neighbours = hash( tuple(frozenset(sorted(new_inlines)))) hash_last_neighbours = hash( tuple(frozenset(sorted(last_inlines)))) if hash_new_neighbours != hash_last_neighbours: self._neighbours = neighbours logging.debug("Change : new neighbours {0} -> {1}".format( last_inlines, new_inlines)) emit_change = True if emit_change: self.changed.emit()