def __handler_status(self, request, context): util.logger.debug(f"peer_outer_service:handler_status ({request.message})") if request.message == "get_stub_manager_to_server": # this case is check only gRPC available return loopchain_pb2.Message(code=message_code.Response.success) channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel channel_stub = StubCollection().channel_stubs[channel_name] if request.message == "check peer status by rs": channel_stub.sync_task().reset_timer(TimerService.TIMER_KEY_CONNECT_PEER) callback = partial(self.__status_update, request.channel) future = asyncio.run_coroutine_threadsafe( channel_stub.async_task().get_status(), self.peer_service.inner_service.loop ) future.add_done_callback(callback) status = self.__get_status_peer_type_data(request.channel) if status is None: return loopchain_pb2.Message(code=message_code.Response.fail) meta = json.loads(request.meta) if request.meta else {} if meta.get("highest_block_height", None) and meta["highest_block_height"] > status["block_height"]: util.logger.spam(f"(peer_outer_service.py:__handler_status) there is difference of height !") channel_stub.sync_task().block_height_sync() status_json = json.dumps(status) return loopchain_pb2.Message(code=message_code.Response.success, meta=status_json)
def __handler_get_configuration(self, request, context): """Get Configuration :param request: proto.Message {meta=configuration_name} :param context: :return: proto.Message {meta=configuration_info(s)} """ if request.meta == '': result = conf.get_all_configurations() else: meta = json.loads(request.meta) conf_name = meta['name'] result = conf.get_configuration(conf_name) if result is None: return loopchain_pb2.Message( code=message_code.Response.fail, message="'" + conf_name + "' is an incorrect configuration name." ) else: json_result = json.dumps(result) return loopchain_pb2.Message( code=message_code.Response.success, meta=json_result )
def __handler_complain_leader(self, request, context): """Complain Leader Peer :param request: proto.Message {message=group_id} :param context: :return: proto.Message {object=leader_peer_object} """ # 현재 leader peer status 확인 후 맞으면 peer id 를 # 아니면 complain 한 peer 로 leader 를 변경 후 응답한다. # 선택된 peer 가 leader 로 동작하고 있는지 확인 후 지정하는데 만약 # get_leader_peer 한 내용과 다르면 AnnounceNewLeader 를 broadcast 하여야 한다. logging.debug("in complain leader (radiostation)") leader_peer = ObjectManager( ).rs_service.channel_manager.get_peer_manager( conf.LOOPCHAIN_DEFAULT_CHANNEL).complain_leader( group_id=request.message) if leader_peer is not None: logging.warning( f"leader_peer after complain({leader_peer.peer_id})") peer_dump = pickle.dumps(leader_peer) return loopchain_pb2.Message(code=message_code.Response.success, object=peer_dump) return loopchain_pb2.Message( code=message_code.Response.fail_no_leader_peer)
def Request(self, request, context): logging.debug("RadioStationService got request: " + str(request)) if request.code in self.__handler_map.keys(): return self.__handler_map[request.code](request, context) return loopchain_pb2.Message(code=message_code.Response.not_treat_message_code)
def __handler_peer_list(self, request, context): message = "All Group Peers count: " + str( len(self.peer_service.peer_list.peer_list[conf.ALL_GROUP_ID])) return loopchain_pb2.Message( code=message_code.Response.success, message=message, meta=str(self.peer_service.peer_list.peer_list))
def __handler_get_balance(self, request, context): """Get Balance Tx for json-rpc request :param request: :param context: :return: """ params = json.loads(request.meta) if 'address' not in params.keys(): return loopchain_pb2.Message(code=message_code.Response.fail_illegal_params) query_request = loopchain_pb2.QueryRequest(params=request.meta, channel=request.channel) response = self.Query(query_request, context) util.logger.spam(f"peer_outer_service:__handler_get_balance response({response})") return loopchain_pb2.Message(code=response.response_code, meta=response.response)
def Request(self, request, context): # util.logger.debug(f"Peer Service got request({request.code})") if request.code in self.__handler_map.keys(): return self.__handler_map[request.code](request, context) return loopchain_pb2.Message(code=message_code.Response.not_treat_message_code)
def GetScoreStatus(self, request, context): """Score Service 의 현재 상태를 요청 한다 :param request: :param context: :return: """ logging.debug("Peer GetScoreStatus request : %s", request) score_status = json.loads("{}") channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel try: score_status_response = self.peer_service.channel_manager.get_score_container_stub( channel_name).call( "Request", loopchain_pb2.Message(code=message_code.Request.status)) logging.debug("Get Score Status : " + str(score_status_response)) if score_status_response.code == message_code.Response.success: score_status = json.loads(score_status_response.meta) except Exception as e: logging.debug("Score Service Already stop by other reason. %s", e) return loopchain_pb2.StatusReply(status=json.dumps(score_status), block_height=0, total_tx=0)
def Request(self, request, context): logging.debug(f"rs_outer_service:Request({request})") if request.code in self.__handler_map.keys(): return self.__handler_map[request.code](request, context) return loopchain_pb2.Message(code=message_code.Response.not_treat_message_code)
def __handler_reconnect_to_rs(self, request, context): logging.warning(f"RS lost peer info (candidate reason: RS restart)") logging.warning(f"try reconnect to RS....") ObjectManager().peer_service.connect_to_radiostation( channel=request.channel, is_reconnect=True) return loopchain_pb2.Message(code=message_code.Response.success)
def __handler_get_leader_peer(self, request, context): """Get Leader Peer :param request: proto.Message {message=group_id} :param context: :return: proto.Message {object=leader_peer_object} """ # TODO 현재는 peer_list.get_leader_peer 가 서브 그룹 리더에 대한 처리를 제공하지 않고 있다. leader_peer = self.__peer_manager.get_leader_peer(group_id=request.message, is_peer=False) if leader_peer is not None: logging.debug(f"leader_peer ({leader_peer.peer_id})") peer_dump = pickle.dumps(leader_peer) return loopchain_pb2.Message(code=message_code.Response.success, object=peer_dump) return loopchain_pb2.Message(code=message_code.Response.fail_no_leader_peer)
def __handler_set_configuration(self, request, context): """Set Configuration :param request: proto.Message {meta=configuration_info} :param context: :return: proto.Message """ meta = json.loads(request.meta) if conf.set_configuration(meta['name'], meta['value']): return loopchain_pb2.Message(code=message_code.Response.success) else: return loopchain_pb2.Message( code=message_code.Response.fail, message='"' + meta['name'] + '" does not exist in the loopchain configuration list.')
def __handler_get_leader_peer(self, request, context): """Get Leader Peer :param request: proto.Message {message=group_id} :param context: :return: proto.Message {object=leader_peer_object} """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if not request.channel else request.channel leader_peer: PeerInfo = ObjectManager().rs_service.channel_manager.get_peer_manager( channel_name).get_leader_peer(group_id=request.message, is_peer=False) if leader_peer is not None: logging.debug(f"leader_peer ({leader_peer.peer_id})") peer_dumped = leader_peer.dump() return loopchain_pb2.Message(code=message_code.Response.success, object=peer_dumped) return loopchain_pb2.Message(code=message_code.Response.fail_no_leader_peer)
def announce_new_leader(self, complained_leader_id, new_leader_id, is_broadcast=True, self_peer_id=None): """Announce New Leader Id to Network :param complained_leader_id: :param new_leader_id: :param is_broadcast: False(notify to RS only), True(broadcast to network include RS) :param self_peer_id: :return: """ util.logger.spam(f"peer_manager:announce_new_leader channel({self.__channel_name}), " f"complained_leader_id({complained_leader_id}), " f"new_leader_id({new_leader_id}), " f"is_broadcast({is_broadcast})") is_rs = ObjectManager().rs_service is not None announce_message = loopchain_pb2.ComplainLeaderRequest( complained_leader_id=complained_leader_id, channel=self.__channel_name, new_leader_id=new_leader_id, message="Announce New Leader" ) # new_leader_peer = self.get_peer(new_leader_id) # Announce New Leader to Radio station try: channel_service = ObjectManager().channel_service if channel_service: response = channel_service.radio_station_stub.call("AnnounceNewLeader", announce_message) if response.response_code == message_code.Response.fail_no_peer_info_in_rs: util.logger.spam( f"peer_manager:announce_new_leader fail no peer info in rs! is_broadcast({is_broadcast})") announce_message.message = message_code.get_response_msg( message_code.Response.fail_no_peer_info_in_rs) ObjectManager().channel_service.connect_to_radio_station(is_reconnect=True) ObjectManager().channel_service.broadcast_scheduler.schedule_broadcast( "Request", loopchain_pb2.Message( code=message_code.Request.peer_reconnect_to_rs, channel=self.__channel_name)) except Exception as e: # logging.debug("in RS there is no peer_service....") is_rs = True if is_broadcast is True: for peer_id in list(self.peer_list[conf.ALL_GROUP_ID]): if new_leader_id == peer_id and is_rs is not True: util.logger.spam(f"Prevent reset leader loop in AnnounceNewLeader message") continue peer_each = self.peer_list[conf.ALL_GROUP_ID][peer_id] stub_manager = self.get_peer_stub_manager(peer_each, conf.ALL_GROUP_ID) try: stub_manager.call_async("AnnounceNewLeader", announce_message, is_stub_reuse=True) except Exception as e: logging.warning("gRPC Exception: " + str(e)) logging.debug("No response target: " + str(peer_each.target))
def __handler_restart_channel(self, request, context): logging.debug(f"Restart_channel({request.channel}) code({request.code}), message({request.message})") ObjectManager().peer_service.start_channel( channel=request.channel, is_restart=True ) return loopchain_pb2.Message(code=message_code.Response.success)
def check_peer_status(self, group_id=None): if group_id is None: group_id = conf.ALL_GROUP_ID nonresponse_peer_list = [] check_leader_peer_count = 0 for peer_id in list(self.__peer_object_list[group_id]): peer_info: PeerInfo = self.peer_list[group_id][peer_id] stub_manager = self.get_peer_stub_manager(peer_info, group_id) peer_object: PeerObject = self.__peer_object_list[group_id][peer_id] try: response = stub_manager.call( "Request", loopchain_pb2.Message( code=message_code.Request.status, channel=self.__channel_name, message="check peer status by rs", meta=json.dumps({"highest_block_height": self.__highest_block_height}) ), is_stub_reuse=True) if response.code != message_code.Response.success: raise Exception peer_object.no_response_count_reset() peer_info.status = PeerStatus.connected peer_status = json.loads(response.meta) if peer_status["state"] == "BlockGenerate": check_leader_peer_count += 1 if peer_status["block_height"] >= self.__highest_block_height: self.__highest_block_height = peer_status["block_height"] except Exception as e: util.apm_event(conf.RADIO_STATION_NAME, { 'event_type': 'DisconnectedPeer', 'peer_name': conf.PEER_NAME, 'channel_name': self.__channel_name, 'data': { 'message': 'there is disconnected peer gRPC Exception: ' + str(e), 'peer_id': peer_info.peer_id}}) logging.warning("there is disconnected peer peer_id(" + peer_info.peer_id + ") gRPC Exception: " + str(e)) peer_object.no_response_count_up() util.logger.spam( f"peer_manager::check_peer_status " f"peer_id({peer_object.peer_info.peer_id}) " f"no response count up({peer_object.no_response_count})") if peer_object.no_response_count >= conf.NO_RESPONSE_COUNT_ALLOW_BY_HEARTBEAT: peer_info.status = PeerStatus.disconnected logging.debug(f"peer status update time: {peer_info.status_update_time}") logging.debug(f"this peer not respond {peer_info.peer_id}") nonresponse_peer_list.append(peer_info) logging.info(f"non response peer list : {nonresponse_peer_list}")
def __handler_peer_list(self, request, context): channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel peer_manager = self.peer_service.channel_manager.get_peer_manager( channel_name) message = "All Group Peers count: " + str( len(peer_manager.peer_list[conf.ALL_GROUP_ID])) return loopchain_pb2.Message(code=message_code.Response.success, message=message, meta=str(peer_manager.peer_list))
def __handler_get_tx_by_address(self, request, context): """Get Transaction by address :param request: :param context: :return: """ params = json.loads(request.meta) address = params.pop('address', None) index = params.pop('index', None) if address is None or index is None: # or params: return loopchain_pb2.Message(code=message_code.Response.fail_illegal_params) channel_stub = StubCollection().channel_stubs[request.channel] tx_list, next_index = channel_stub.sync_task().get_tx_by_address(address, index) return loopchain_pb2.Message(code=message_code.Response.success, meta=str(next_index), object=pickle.dumps(tx_list))
def Request(self, request, context): logging.debug(f"rs_admin_service:Request({request})") logging.debug(f"get context : {context}") if request.code in self.__handler_map.keys(): return self.__handler_map[request.code](request, context) logging.warning( f"rs_admin_service:Request not treat message code({request.code})") return loopchain_pb2.Message( code=message_code.Response.not_treat_message_code)
def __handler_peer_list(self, request, context): channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel channel_stub = StubCollection().channel_stubs[channel_name] all_group_peer_list_str, peer_list_str = channel_stub.sync_task().get_peer_list() message = "All Group Peers count: " + all_group_peer_list_str return loopchain_pb2.Message( code=message_code.Response.success, message=message, meta=peer_list_str)
def __handler_restart_channel(self, request, context): """ :param request: :param context: :return: """ util.logger.spam(f"rs_admin_service:__handler_restart_channel") message = loopchain_pb2.Message( code=message_code.Request.peer_restart_channel, channel=request.channel, message="restart channel") ObjectManager().rs_service.channel_manager.broadcast( request.channel, "Request", message, timeout=conf.CHANNEL_RESTART_TIMEOUT) return loopchain_pb2.Message(code=message_code.Response.success)
def __handler_get_total_supply(self, request, context): """Get Total Supply :param request: :param context: :return: """ query_request = loopchain_pb2.QueryRequest(params=request.meta, channel=request.channel) response = self.Query(query_request, context) util.logger.spam(f"peer_outer_service:__handler_get_total_supply response({response})") return loopchain_pb2.Message(code=response.response_code, meta=response.response)
def __handler_status(self, request, context): util.logger.debug(f"peer_outer_service:handler_status") channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel status = dict() if ObjectManager().peer_service is not None: status['peer_type'] = \ str(self.peer_service.channel_manager.get_block_manager(channel_name).peer_type) else: status['peer_type'] = '0' status_json = json.dumps(status) return loopchain_pb2.Message(code=message_code.Response.success, meta=status_json)
def Query(self, request, context): """Score 의 invoke 로 생성된 data 에 대한 query 를 수행한다.""" channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel # TODO 입력값 오류를 검사하는 방법을 고려해본다, 현재는 json string 여부만 확인 if util.check_is_json_string(request.params): logging.debug(f'Query request with {request.params}') try: response_from_score_service = \ self.peer_service.channel_manager.get_score_container_stub(channel_name).call( method_name="Request", message=loopchain_pb2.Message(code=message_code.Request.score_query, meta=request.params), timeout=conf.SCORE_QUERY_TIMEOUT, is_raise=True ) response = response_from_score_service.meta util.apm_event( self.peer_service.peer_id, { 'event_type': 'Query', 'peer_id': self.peer_service.peer_id, 'data': { 'score_query': json.loads(request.params) } }) except Exception as e: logging.error(f'Execute Query Error : {e}') if isinstance(e, _Rendezvous): # timeout 일 경우 if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED: return loopchain_pb2.QueryReply( response_code=message_code.Response.timeout_exceed, response="") return loopchain_pb2.QueryReply( response_code=message_code.Response.fail, response="") else: return loopchain_pb2.QueryReply( response_code=message_code.Response.fail_validate_params, response="") if util.check_is_json_string(response): # TODO 응답값 오류를 검사하는 방법을 고려해본다, 현재는 json string 여부만 확인 response_code = message_code.Response.success else: response_code = message_code.Response.fail return loopchain_pb2.QueryReply(response_code=response_code, response=response)
def __handler_rs_send_channel_manage_info_to_rs(self, request, context): """ :param request.code: message_code.Request.rs_send_channel_manage_info_to_rs :param request.meta: channel_manage_info :param request.message: from gtool or another rs """ util.logger.spam( f"rs_admin_service:__handler_rs_send_channel_manage_info_to_rs") # TODO rs 의 admin_manager 에 channel_manage_info 반영, 자신의 json 파일에도 반영 # TODO 이 메시지가 gtool 에서 왔다면, 다른 rs 에도 전송한다.(rs 이중화 완료까지 보류) 이때는 메시지를 변경하여 출처를 gtool 이 아닌 rs 로 수정한다. return loopchain_pb2.Message(code=message_code.Response.success)
def __handler_delete_peer(self, request, context): util.logger.spam( f"rs_admin_service:__handler_delete_peer target({request.message})" ) self.__admin_manager.save_channel_manage_data(json.loads(request.meta)) peer_target = request.message channel_manager_data = json.loads(request.meta) channel_manager = ObjectManager().rs_service.channel_manager for channel in channel_manager_data: util.logger.spam( f"rs_admin_service:__handler_delete_peer channel({channel})") channel_manager.get_peer_manager(channel).\ remove_peer_by_target(channel_manager, peer_target) return loopchain_pb2.Message(code=message_code.Response.success)
def __handler_rs_send_channel_manage_info_to_rs(self, request, context): """ :param request.code: message_code.Request.rs_send_channel_manage_info_to_rs :param request.meta: channel_manage_info :param request.message: from gtool or another rs """ util.logger.spam( f"rs_admin_service:__handler_rs_send_channel_manage_info_to_rs") self.__admin_manager.save_channel_manage_data(json.loads(request.meta)) logging.debug( f"rs_admin_service:__handler_rs_send_channel_manage_info_to_rs " f"new channel_manage_data({self.__admin_manager.json_data})") return loopchain_pb2.Message(code=message_code.Response.success)
def __handler_get_tx_result(self, request, context): """Get Transaction Result for json-rpc request :param request: :param context: :return: """ util.logger.spam(f"checking for test, code: {request.code}") util.logger.spam(f"checking for test, channel name: {request.channel}") util.logger.spam(f"checking for test, message: {request.message}") util.logger.spam(f"checking for test, meta: {json.loads(request.meta)}") params = json.loads(request.meta) util.logger.spam(f"params tx_hash({params['tx_hash']})") return loopchain_pb2.Message(code=message_code.Response.success)
def leader_complain_to_rs(self, group_id, is_announce_new_peer=True) -> PeerInfo: """When fail to find a leader, Ask to RS. RS check leader and notify leader info or set new leader first peer who complained :param group_id: :param is_announce_new_peer: :return: """ logging.debug(f"peer_manager:leader_complain_to_rs") if ObjectManager().peer_service.stub_to_radiostation is None: return None peer_self = self.get_peer(ObjectManager().peer_service.peer_id, ObjectManager().peer_service.group_id) peer_self_dumped = peer_self.dump() response = ObjectManager().peer_service.stub_to_radiostation.call( "Request", loopchain_pb2.Message( code=message_code.Request.peer_complain_leader, message=group_id, object=peer_self_dumped)) if response is not None and response.code == message_code.Response.success: try: leader_peer = PeerInfo.load(response.object) except Exception as e: traceback.print_exc() logging.error( f"Invalid peer info. Check your Radio Station. exception={e}" ) return None self.set_leader_peer(leader_peer) else: leader_peer = None # logging.debug(str(leader_peer)) # self.set_leader_peer(leader_peer) # # if is_announce_new_peer: # self.announce_new_leader("", leader_peer.peer_id) return leader_peer
def Stop(self, request, context): """Peer를 중지시킨다 :param request: 중지요청 :param context: :return: 중지결과 """ if request is not None: logging.info('Peer will stop... by: ' + request.reason) try: response = self.peer_service.stub_to_score_service.call( "Request", loopchain_pb2.Message(code=message_code.Request.stop)) logging.debug("try stop score container: " + str(response)) except Exception as e: logging.debug("Score Service Already stop by other reason. %s", e) self.peer_service.service_stop() return loopchain_pb2.StopReply(status="0")