def check_path_request_errors( self, source: Address, target: Address, value: PaymentAmount, reachability_state: AddressReachabilityProtocol, ) -> Optional[str]: """Checks for basic problems with the path requests. Returns error message or `None`""" with opentracing.tracer.start_span("check_path_request_errors"): if (reachability_state.get_address_reachability(source) is not AddressReachability.REACHABLE): return "Source not online" if (reachability_state.get_address_reachability(target) is not AddressReachability.REACHABLE): return "Target not online" if not any(self.G.edges(source)): return "No channel from source" if not any(self.G.edges(target)): return "No channel to target" source_capacities = [ view.capacity for _, _, view in self.G.out_edges(source, data="view") ] if max(source_capacities) < value: debug_capacities = [ (to_checksum_address(a), to_checksum_address(b), view.capacity) for a, b, view in self.G.out_edges(source, data="view") ] log.debug("Insufficient capacities", capacities=debug_capacities) message = ( f"Source does not have a channel with sufficient capacity " f"(current capacities: {source_capacities} < requested amount: " f" {value})") return message target_capacities = [ view.capacity for _, _, view in self.G.in_edges(target, data="view") ] if max(target_capacities) < value: return "Target does not have a channel with sufficient capacity (%s < %s)" % ( target_capacities, value, ) try: next( nx.shortest_simple_paths(G=self.G, source=source, target=target)) except NetworkXNoPath: return "No route from source to target" return None
def prune_graph(graph: DiGraph, reachability_state: AddressReachabilityProtocol) -> DiGraph: """Prunes the given `graph` of all channels where the participants are not reachable.""" pruned_graph = DiGraph() for p1, p2 in graph.edges: nodes_online = ( reachability_state.get_address_reachability(p1) == AddressReachability.REACHABLE and reachability_state.get_address_reachability(p2) == AddressReachability.REACHABLE ) if nodes_online: pruned_graph.add_edge(p1, p2, view=graph[p1][p2]["view"]) pruned_graph.add_edge(p2, p1, view=graph[p2][p1]["view"]) return pruned_graph
def suggest_partner(self, reachability_state: AddressReachabilityProtocol, limit: int = 5) -> List[Dict[str, Any]]: """Suggest good partners for Raiden nodes joining the token network""" with opentracing.tracer.start_span("find_centrality"): # centrality centrality_of_node = nx.algorithms.centrality.closeness_centrality( self.G) # uptime, only include online nodes uptime_of_node = {} now = datetime.utcnow() for node in self.G.nodes: node_reach_state = reachability_state.get_address_reachability_state( node) if node_reach_state.reachability == AddressReachability.REACHABLE: uptime_of_node[node] = (now - node_reach_state.time).total_seconds() # capacity capacity_of_node = {} for node in uptime_of_node: channel_views = [ channel_data["view"] for _, _, channel_data in self.G.edges(node, data=True) ] capacity_of_node[node] = sum(cv.capacity for cv in channel_views) # sort by overall score suggestions = [ dict( address=to_checksum_address(node), score=centrality_of_node[node] * uptime * capacity_of_node[node], centrality=centrality_of_node[node], uptime=uptime, capacity=capacity_of_node[node], ) for node, uptime in uptime_of_node.items() ] return sorted(suggestions, key=lambda n: -n["score"])[:limit]