def __make_peer_info(self, peer_id, group_id): peer_info = loopchain_pb2.PeerRequest() peer_info.peer_target = peer_id + "_target" peer_info.peer_type = loopchain_pb2.PEER peer_info.peer_id = peer_id peer_info.group_id = group_id return peer_info
def __subscribe_to_peer_list(self): peer_object = self.peer_manager.get_peer(ChannelProperty().peer_id) peer_request = loopchain_pb2.PeerRequest( channel=ChannelProperty().name, peer_target=ChannelProperty().peer_target, peer_id=ChannelProperty().peer_id, group_id=ChannelProperty().group_id, node_type=ChannelProperty().node_type, peer_order=peer_object.order ) self.__broadcast_scheduler.schedule_broadcast("Subscribe", peer_request)
async def __subscribe_call_to_stub(self, peer_stub, peer_type): if self.is_support_node_function(conf.NodeFunction.Vote): await peer_stub.call_async( "Subscribe", loopchain_pb2.PeerRequest( channel=ChannelProperty().name, peer_target=ChannelProperty().peer_target, peer_type=peer_type, peer_id=ChannelProperty().peer_id, group_id=ChannelProperty().group_id, node_type=ChannelProperty().node_type ), ) else: await self.__subscribe_call_from_citizen()
async def __subscribe_call_to_stub_by_method(self, peer_stub, peer_type): if self.is_support_node_function(conf.NodeFunction.Vote): await peer_stub.call_async( "Subscribe", loopchain_pb2.PeerRequest( channel=ChannelProperty().name, peer_target=ChannelProperty().peer_target, peer_type=peer_type, peer_id=ChannelProperty().peer_id, group_id=ChannelProperty().group_id, node_type=ChannelProperty().node_type ), ) else: util.logger.spam(f"channel_service:__subscribe_call_to_stub_by_method " f"peer_target({ChannelProperty().rest_target})") response = self.__subscribe_call_to_rs_stub(peer_stub) if response['response_code'] != message_code.Response.success: error = f"subscribe fail to peer_target({ChannelProperty().radio_station_target}) " \ f"reason({response['message']})" await StubCollection().peer_stub.async_task().stop(message=error)
def __connect_to_radiostation(self): """RadioStation 접속 :return: 접속정보, 실패시 None """ logging.debug("try to connect to radiostation") self.__stub_to_radio_station = StubManager.get_stub_manager_to_server( self.__radio_station_target, loopchain_pb2_grpc.RadioStationStub, conf.CONNECTION_RETRY_TIMEOUT_TO_RS) if self.__stub_to_radio_station is None: logging.warning("fail make stub to Radio Station!!") return None token = None if self.__auth.is_secure: peer_self = self.__peer_manager.get_peer(self.peer_id) token = None if peer_self is not None: token = peer_self.token logging.debug("Self Peer Token : %s", token) # 토큰 유효시간이 지나면 다시 생성 요청 if token is not None and self.__auth.get_token_time(token) is None: token = None self.__auth.set_peer_info(self.peer_id, self.__peer_target, self.group_id, self.__peer_type) cert_bytes = self.__auth.get_cert_bytes() if token is None: # 서버로부터 난수 수신 # response = util.request_server_in_time(self.__stub_to_radio_station.ConnectPeer, # loopchain_pb2.PeerRequest( # peer_object=b'', # peer_id=self.peer_id, # peer_target=self.__peer_target, # group_id=self.group_id, # peer_type=self.__peer_type, # token=conf.TOKEN_TYPE_CERT + cert_bytes.hex()) # ) response = self.__stub_to_radio_station.call( "ConnectPeer", loopchain_pb2.PeerRequest(peer_object=b'', peer_id=self.peer_id, peer_target=self.__peer_target, group_id=self.group_id, peer_type=self.__peer_type, token=conf.TOKEN_TYPE_CERT + cert_bytes.hex()), conf.GRPC_TIMEOUT) rand_key = None if response is not None and response.status == message_code.Response.success: logging.debug("Received Random : %s", response.more_info) if len(response.more_info) is not 32: # 토큰 크기가 16바이트가 아니면 접속을 할 수 없습니다. logging.debug('서버로부터 수신한 토큰 길이는 16바이트가 되어야 합니다.') else: rand_key = response.more_info else: return response # 난수와 Peer 정보에 서명 if rand_key is None: return None else: sign = self.__auth.generate_request_sign(rand_key=rand_key) token = conf.TOKEN_TYPE_SIGN + sign.hex() else: self.__auth.add_token(token) # 공통 부분 # response = util.request_server_in_time(self.__stub_to_radio_station.ConnectPeer, # loopchain_pb2.PeerRequest( # peer_object=b'', # peer_id=self.peer_id, # peer_target=self.__peer_target, # group_id=self.group_id, # peer_type=self.__peer_type, # token=token # )) response = self.__stub_to_radio_station.call( "ConnectPeer", loopchain_pb2.PeerRequest(peer_object=b'', peer_id=self.peer_id, peer_target=self.__peer_target, group_id=self.group_id, peer_type=self.__peer_type, token=token), conf.GRPC_CONNECTION_TIMEOUT) if response is not None and response.status == message_code.Response.success: if self.__auth.is_secure: logging.debug("Received Token : %s", response.more_info) # Radiostation으로부터 수신한 토큰 검증 if len(response.more_info) < 9: # 토큰 크기가 8 + 1바이트 보다 크지 아니면 접속을 할 수 없습니다. logging.debug('서버로부터 수신한 토큰 길이는 9바이트 이상이 되어야 합니다.') response.status = message_code.Response.fail_validate_params response.more_info = "Invalid Token Data" else: token = response.more_info tag = token[:2] if tag == conf.TOKEN_TYPE_TOKEN: if self.__auth.verify_token(token): logging.debug("토큰 검증에 성공하였습니다.") self.__auth.add_token(token) else: logging.debug("토큰 검증에 실패하였습니다.") response.status = message_code.Response.fail_validate_params response.more_info = "Invalid Token Signature" return response
def __connect_to_radiostation(self): """RadioStation 접속 :return: 접속정보, 실패시 None """ logging.debug("try to connect to radiostation") self.__stub_to_radio_station = StubManager.get_stub_manager_to_server( self.__radio_station_target, loopchain_pb2_grpc.RadioStationStub, conf.CONNECTION_RETRY_TIMEOUT_TO_RS) if self.__stub_to_radio_station is None: logging.warning("fail make stub to Radio Station!!") return None token = None if self.__auth.is_secure: self.__peer_object = self.__peer_manager.get_peer(self.peer_id) token = None if self.__peer_object is not None: token = self.__peer_object.token logging.debug("Self Peer Token : %s", token) # 토큰 유효시간이 지나면 다시 생성 요청 if token is not None and self.__auth.get_token_time(token) is None: token = None self.__auth.set_peer_info(self.peer_id, self.__peer_target, self.group_id, self.__peer_type) cert_bytes = self.__auth.get_cert_bytes() if token is None: # 서버로부터 난수 수신 # response = util.request_server_in_time(self.__stub_to_radio_station.ConnectPeer, # loopchain_pb2.PeerRequest( # peer_object=b'', # peer_id=self.peer_id, # peer_target=self.__peer_target, # group_id=self.group_id, # peer_type=self.__peer_type, # token=conf.TOKEN_TYPE_CERT + cert_bytes.hex()) # ) response = self.__stub_to_radio_station.call( "ConnectPeer", loopchain_pb2.PeerRequest(peer_object=b'', peer_id=self.peer_id, peer_target=self.__peer_target, group_id=self.group_id, peer_type=self.__peer_type, token=conf.TOKEN_TYPE_CERT + cert_bytes.hex()), conf.GRPC_TIMEOUT) rand_key = None if response is not None and response.status == message_code.Response.success: logging.debug("Received Random : %s", response.more_info) if len(response.more_info) is not 32: # 토큰 크기가 16바이트가 아니면 접속을 할 수 없습니다. logging.debug('서버로부터 수신한 토큰 길이는 16바이트가 되어야 합니다.') else: rand_key = response.more_info else: return response # 난수와 Peer 정보에 서명 if rand_key is None: return None else: sign = self.__auth.generate_request_sign(rand_key=rand_key) token = conf.TOKEN_TYPE_SIGN + sign.hex() else: self.__auth.add_token(token) # 공통 부분 # response = util.request_server_in_time(self.__stub_to_radio_station.ConnectPeer, # loopchain_pb2.PeerRequest( # peer_object=b'', # peer_id=self.peer_id, # peer_target=self.__peer_target, # group_id=self.group_id, # peer_type=self.__peer_type, # token=token # )) response = self.__stub_to_radio_station.call( "ConnectPeer", loopchain_pb2.PeerRequest(peer_object=b'', peer_id=self.peer_id, peer_target=self.__peer_target, group_id=self.group_id, peer_type=self.__peer_type, token=token), conf.GRPC_CONNECTION_TIMEOUT) if response is not None and response.status == message_code.Response.success: if self.__auth.is_secure: logging.debug("Received Token : %s", response.more_info) # Radiostation으로부터 수신한 토큰 검증 if len(response.more_info) < 9: # 토큰 크기가 8 + 1바이트 보다 크지 아니면 접속을 할 수 없습니다. logging.debug('서버로부터 수신한 토큰 길이는 9바이트 이상이 되어야 합니다.') response.status = message_code.Response.fail_validate_params response.more_info = "Invalid Token Data" else: token = response.more_info tag = token[:2] if tag == conf.TOKEN_TYPE_TOKEN: if self.__auth.verify_token(token): logging.debug("토큰 검증에 성공하였습니다.") self.__auth.add_token(token) else: logging.debug("토큰 검증에 실패하였습니다.") response.status = message_code.Response.fail_validate_params response.more_info = "Invalid Token Signature" logging.debug("Connect to radiostation: " + str(response)) is_peer_list_from_rs = False if response is not None and response.status == message_code.Response.success: # RS 의 응답이 있으면 peer_list 는 RS 가 전달한 결과로 업데이트 된다. # 없는 경우 local 의 level DB 로 부터 읽어드린 값을 default 로 사용하게 된다. # TODO RS 는 어떻게 신뢰하지? RS 가 새로운 피어의 참여를 승인하더라도 참여한 피어 목록은 더 신뢰할만한 방식으로 보호가 필요하지 않나? # 누군가 RS 를 죽인다면 RS 인척 가짜로 이루어진 피어 리스트를 전송하면 네트워크를 파괴할 수 있지 않나? # 피어의 참여는 RS 가 승인한 다음 블록에 담아서 블록체인에 추가하면 어떨까? peer_list_data = pickle.loads(response.peer_list) self.__peer_manager.load(peer_list_data, False) self.__common_service.save_peer_list(self.__peer_manager) logging.debug("peer list update: " + self.__peer_manager.get_peers_for_debug()) is_peer_list_from_rs = True else: logging.debug("using local peer list: " + self.__peer_manager.get_peers_for_debug()) return is_peer_list_from_rs