def GetLastBlockHash(self, request, context): """ 마지막 블럭 조회 :param request: 블럭요청 :param context: :return: 마지막 블럭 """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel # Peer To Client block_manager = self.peer_service.channel_manager.get_block_manager( channel_name) last_block = block_manager.get_blockchain().last_block response_code, response_msg = message_code.get_response( message_code.Response.fail) block_hash = None if last_block is not None: response_code, response_msg = message_code.get_response( message_code.Response.success) block_hash = last_block.block_hash return loopchain_pb2.BlockReply( response_code=response_code, message=(response_msg + (" This is for block height sync", " This is for Test Validation" )[block_manager.peer_type == loopchain_pb2.PEER]), block_hash=block_hash)
def add_unconfirm_block(self, block_unloaded, channel_name=None): if channel_name is None: channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL block = pickle.loads(block_unloaded) block_hash = block.block_hash response_code, response_msg = message_code.get_response( message_code.Response.fail_validate_block) # block 검증 block_is_validated = False try: block_is_validated = Block.validate(block) except Exception as e: logging.error(e) if block_is_validated: # broadcast 를 받으면 받은 블럭을 검증한 후 검증되면 자신의 blockchain 의 unconfirmed block 으로 등록해 둔다. confirmed, reason = \ self.__channel_manager.get_block_manager(channel_name).get_blockchain().add_unconfirm_block(block) if confirmed: response_code, response_msg = message_code.get_response( message_code.Response.success_validate_block) elif reason == "block_height": # Announce 되는 블럭과 자신의 height 가 다르면 Block Height Sync 를 다시 시도한다. self.__channel_manager.get_block_manager( channel_name).block_height_sync() return response_code, response_msg, block_hash
def AnnounceConfirmedBlock(self, request, context): """Block Generator 가 announce 하는 인증된 블록의 대한 hash 를 전달받는다. :param request: BlockAnnounce of loopchain.proto :param context: gRPC parameter :return: CommonReply of loopchain.proto """ # Peer To BlockGenerator logging.debug("AnnounceConfirmedBlock block hash: " + request.block_hash) response_code, response_msg = message_code.get_response( message_code.Response.fail_announce_block) confirmed_block = pickle.loads(request.block) logging.debug(f"block \n" f"peer_id({confirmed_block.peer_id})\n" f"made_block_count({confirmed_block.made_block_count})\n" f"is_divided_block({confirmed_block.is_divided_block})") if len(request.block) > 0: logging.warning( "AnnounceConfirmedBlock without Consensus ====================" ) # 아래의 return 값을 확인하지 않아도 예외인 경우 아래 except 에서 확인된다. self.peer_service.add_unconfirm_block(request.block) try: self.peer_service.block_manager.confirm_block(request.block_hash) response_code, response_msg = message_code.get_response( message_code.Response.success_announce_block) except (BlockchainError, BlockInValidError, BlockError) as e: logging.error("AnnounceConfirmedBlock: " + str(e)) return loopchain_pb2.CommonReply(response_code=response_code, message=response_msg)
def GetTx(self, request, context): """get transaction :param request: tx_hash :param context:channel_loopchain_default :return: """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel channel_stub = StubCollection().channel_stubs[channel_name] tx = channel_stub.sync_task().get_tx(request.tx_hash) response_code, response_msg = message_code.get_response(message_code.Response.fail) response_meta = "" response_data = "" response_sign = b'' response_public_key = b'' if tx is not None: response_code, response_msg = message_code.get_response(message_code.Response.success) response_meta = json.dumps(tx.meta) response_data = tx.get_data().decode(conf.PEER_DATA_ENCODING) response_sign = tx.signature response_public_key = tx.public_key return loopchain_pb2.GetTxReply(response_code=response_code, meta=response_meta, data=response_data, signature=response_sign, public_key=response_public_key, more_info=response_msg)
def add_unconfirm_block(self, block_unloaded): block = pickle.loads(block_unloaded) block_hash = block.block_hash response_code, response_msg = message_code.get_response( message_code.Response.fail_validate_block) # block 검증 block_is_validated = False try: block_is_validated = block.validate() except (BlockInValidError, BlockError, TransactionInValidError) as e: logging.error(e) if block_is_validated: # broadcast 를 받으면 받은 블럭을 검증한 후 검증되면 자신의 blockchain 의 unconfirmed block 으로 등록해 둔다. confirmed, reason = self.__block_manager.get_blockchain( ).add_unconfirm_block(block) if confirmed: response_code, response_msg = message_code.get_response( message_code.Response.success_validate_block) elif reason == "block_height": # Announce 되는 블럭과 자신의 height 가 다르면 Block Height Sync 를 다시 시도한다. self.block_height_sync(self.__stub_to_blockgenerator) return response_code, response_msg, block_hash
def GetLastBlockHash(self, request, context): """ 마지막 블럭 조회 :param request: 블럭요청 :param context: :return: 마지막 블럭 """ # Peer To Client last_block = self.peer_service.block_manager.get_blockchain( ).last_block response_code, response_msg = message_code.get_response( message_code.Response.fail) block_hash = None if last_block is not None: response_code, response_msg = message_code.get_response( message_code.Response.success) block_hash = last_block.block_hash return loopchain_pb2.BlockReply( response_code=response_code, message=(response_msg + (" This is for block height sync", " This is for Test Validation" )[self.peer_service.peer_type == loopchain_pb2.PEER]), block_hash=block_hash)
def GetTx(self, request, context): """ 트랜잭션을 가져옵니다. :param request: tx_hash :param context: :return: """ tx = self.peer_service.block_manager.get_tx(request.tx_hash) # TODO 지금은 일반적인 fail 메시지로만 처리한다. 상세화 여지 있음, 필요시 추가 가능 (by winDy) response_code, response_msg = message_code.get_response( message_code.Response.fail) response_meta = "" response_data = "" if tx is not None: response_code, response_msg = message_code.get_response( message_code.Response.success) response_meta = json.dumps(tx.get_meta()) response_data = tx.get_data().decode(conf.PEER_DATA_ENCODING) return loopchain_pb2.GetTxReply(response_code=response_code, meta=response_meta, data=response_data, more_info=response_msg)
def GetTx(self, request, context): """get transaction :param request: tx_hash :param context:channel_loopchain_default :return: """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel # logging.debug(f"peer_outer_service::GetTx channel({channel_name})") tx = self.peer_service.channel_manager.get_block_manager( channel_name).get_tx(request.tx_hash) # TODO 지금은 일반적인 fail 메시지로만 처리한다. 상세화 여지 있음, 필요시 추가 가능 (by winDy) response_code, response_msg = message_code.get_response( message_code.Response.fail) response_meta = "" response_data = "" response_sign = b'' response_public_key = b'' if tx is not None: response_code, response_msg = message_code.get_response( message_code.Response.success) response_meta = json.dumps(tx.meta) response_data = tx.get_data().decode(conf.PEER_DATA_ENCODING) response_sign = tx.signature response_public_key = tx.public_key return loopchain_pb2.GetTxReply(response_code=response_code, meta=response_meta, data=response_data, signature=response_sign, public_key=response_public_key, more_info=response_msg)
def vote_unconfirmed_block(self, block_hash, is_validated): logging.debug( f"block_manager:vote_unconfirmed_block ({self.channel_name}/{is_validated})" ) if is_validated: vote_code, message = message_code.get_response( message_code.Response.success_validate_block) else: vote_code, message = message_code.get_response( message_code.Response.fail_validate_block) block_vote = loopchain_pb2.BlockVote( vote_code=vote_code, channel=self.channel_name, message=message, block_hash=block_hash, peer_id=self.__peer_id, group_id=ChannelProperty().group_id) self.candidate_blocks.add_vote(block_hash, ChannelProperty().group_id, ChannelProperty().peer_id, is_validated) self.__channel_service.broadcast_scheduler.schedule_broadcast( "VoteUnconfirmedBlock", block_vote)
def AnnounceUnconfirmedBlock(self, request, context): """수집된 tx 로 생성한 Block 을 각 peer 에 전송하여 검증을 요청한다. :param request: :param context: :return: """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel logging.debug( f"peer_outer_service::AnnounceUnconfirmedBlock channel({channel_name})" ) unconfirmed_block = pickle.loads(request.block) logging.warning("Black Peer makes Fail validate Message by intention!") vote_code, message = message_code.get_response( message_code.Response.fail_validate_block) block_vote = loopchain_pb2.BlockVote( vote_code=vote_code, channel=channel_name, message=message, block_hash=unconfirmed_block.block_hash, peer_id=ObjectManager().peer_service.peer_id, group_id=ObjectManager().peer_service.group_id) self.peer_service.common_service.broadcast("VoteUnconfirmedBlock", block_vote) return loopchain_pb2.CommonReply( response_code=message_code.Response.success, message="success")
def AnnounceUnconfirmedBlock(self, request, context): """수집된 tx 로 생성한 Block 을 각 peer 에 전송하여 검증을 요청한다. :param request: :param context: :return: """ # self.__block_manager.add_unconfirmed_block(request.block) unconfirmed_block = pickle.loads(request.block) logging.warning("Black Peer makes Fail validate Message by intention!") vote_code, message = message_code.get_response( message_code.Response.fail_validate_block) self.peer_service.stub_to_blockgenerator.call( "VoteUnconfirmedBlock", loopchain_pb2.BlockVote( vote_code=vote_code, message=message, block_hash=unconfirmed_block.block_hash, peer_id=ObjectManager().peer_service.peer_id, group_id=ObjectManager().peer_service.group_id)) return loopchain_pb2.CommonReply( response_code=message_code.Response.success, message="success")
def vote_unconfirmed_block(self, block_hash, is_validated, channel): logging.debug(f"vote_unconfirmed_block ({channel})") if is_validated: vote_code, message = message_code.get_response(message_code.Response.success_validate_block) else: vote_code, message = message_code.get_response(message_code.Response.fail_validate_block) block_vote = loopchain_pb2.BlockVote( vote_code=vote_code, channel=channel, message=message, block_hash=block_hash, peer_id=self.__peer_id, group_id=ObjectManager().peer_service.group_id) self.broadcast("VoteUnconfirmedBlock", block_vote)
def vote_unconfirmed_block(self, block_hash, is_validated): logging.debug("vote_unconfirmed_block ....") if is_validated: vote_code, message = message_code.get_response(message_code.Response.success_validate_block) else: vote_code, message = message_code.get_response(message_code.Response.fail_validate_block) if self.__stub_to_blockgenerator is not None: self.__stub_to_blockgenerator.call( "VoteUnconfirmedBlock", loopchain_pb2.BlockVote( vote_code=vote_code, message=message, block_hash=block_hash, peer_id=ObjectManager().peer_service.peer_id, group_id=ObjectManager().peer_service.group_id) ) else: logging.error("No block generator stub!")
async def post(self, request): request_body_json = request.json result, verify_message = self.__validate_query_request( request_body_json) query_data = dict() if result is False: logging.warning(verify_message) message = message_code.get_response( message_code.Response.fail_validate_params) query_data['response_code'] = str(message[0].value) query_data['response'] = message[1] + '. ' + verify_message else: request_body_dump = json.dumps(request_body_json) channel = get_channel_name_from_json(request.json) try: grpc_response = ServerComponents().query( request_body_dump, channel) if grpc_response is None: query_data['response'] = str(grpc_response) query_data['response_code'] = str( message_code.Response.not_treat_message_code) else: logging.debug(f"query result : {grpc_response}") query_data['response_code'] = str( grpc_response.response_code) try: query_data['response'] = json.loads( grpc_response.response) except json.JSONDecodeError as e: logging.warning( "your response is not json, your response(" + str(grpc_response.response) + ")") query_data['response'] = grpc_response.response except _Rendezvous as e: logging.error(f'Execute Query Error : {e}') if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED: logging.debug("gRPC timeout !!!") query_data['response_code'] = str( message_code.Response.timeout_exceed) return response.json(query_data)
def GetLastBlockHash(self, request, context): """ 마지막 블럭 조회 :param request: 블럭요청 :param context: :return: 마지막 블럭 """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel # Peer To Client channel_stub = StubCollection().channel_stubs[channel_name] response_code, block_hash, block_data_json, tx_data_json_list = \ channel_stub.sync_task().get_block( block_height=-1, block_hash='', block_data_filter='block_hash', tx_data_filter='') response_code, response_msg = message_code.get_response(response_code) return loopchain_pb2.BlockReply(response_code=response_code, message=response_msg, block_hash=block_hash)
def GetLastBlockHash(self, request, context): """ 마지막 블럭 조회 :param request: 블럭요청 :param context: :return: 마지막 블럭 """ channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel # Peer To Client channel_stub = StubCollection().channel_stubs[channel_name] future = asyncio.run_coroutine_threadsafe( channel_stub.async_task().get_block( block_height=-1, block_hash='', block_data_filter='block_hash', tx_data_filter='' ), self.peer_service.inner_service.loop ) response_code, block_hash, _, block_data_json, tx_data_json_list = future.result() response_code, response_msg = message_code.get_response(response_code) return loopchain_pb2.BlockReply(response_code=response_code, message=response_msg, block_hash=block_hash)
def ConnectPeer(self, request: loopchain_pb2.ConnectPeerRequest, context): """RadioStation 에 접속한다. 응답으로 기존의 접속된 Peer 목록을 받는다. :param request: PeerRequest :param context: :return: ConnectPeerReply """ logging.info(f"Trying to connect peer: {request.peer_id}") if conf.ENABLE_RADIOSTATION_HEARTBEAT: timer_key = f"{TimerService.TIMER_KEY_RS_HEARTBEAT}_{request.channel}" if timer_key not in ObjectManager( ).rs_service.timer_service.timer_list.keys(): ObjectManager().rs_service.timer_service.add_timer( timer_key, Timer( target=timer_key, duration=conf.SLEEP_SECONDS_IN_RADIOSTATION_HEARTBEAT, is_repeat=True, callback=ObjectManager().rs_service.check_peer_status, callback_kwargs={"channel": request.channel})) if conf.ENABLE_CHANNEL_AUTH: if request.peer_target not in ObjectManager( ).rs_service.admin_manager.get_peer_list_by_channel( request.channel): status, reason = message_code.get_response( message_code.Response.fail_invalid_peer_target) return loopchain_pb2.ConnectPeerReply(status=status, peer_list=b'', more_info=reason) channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if not request.channel else request.channel logging.debug(f"ConnectPeer channel_name({channel_name})") logging.debug(f"Connect Peer " f"\nPeer_id : {request.peer_id}" f"\nPeer_target : {request.peer_target}" f"\nChannel : {request.channel}") peer = PeerInfo(request.peer_id, request.group_id, request.peer_target, PeerStatus.unknown, cert=request.cert) util.logger.spam(f"service::ConnectPeer try add_peer") # when first peer ConnectPeer to RS, # RS need rebuild peer list from db. # For prevent leader split by RS. with self.__load_peer_manager_lock: peer_manager = ObjectManager().rs_service.channel_manager.\ get_peer_manager(channel_name) util.logger.spam(f"before load peer_manager " f"peer_count({peer_manager.get_peer_count()})") if peer_manager.get_peer_count() == 0: util.logger.spam(f"try load peer_manager from db") peer_manager = ObjectManager().rs_service.admin_manager.\ load_peer_manager(channel_name) ObjectManager().rs_service.channel_manager.\ set_peer_manager(channel_name, peer_manager) util.logger.spam(f"after load peer_manager " f"peer_count({peer_manager.get_peer_count()})") peer_order = peer_manager.add_peer(peer) peer_list_dump = b'' status, reason = message_code.get_response(message_code.Response.fail) if peer_order > 0: try: peer_list_dump = peer_manager.dump() status, reason = message_code.get_response( message_code.Response.success) except pickle.PicklingError as e: logging.warning("fail peer_list dump") reason += " " + str(e) # save current peer_manager after ConnectPeer from new peer. ObjectManager().rs_service.admin_manager.save_peer_manager( channel_name, peer_manager) return loopchain_pb2.ConnectPeerReply(status=status, peer_list=peer_list_dump, channels=None, more_info=reason)
def ConnectPeer(self, request, context): """RadioStation 에 접속한다. 응답으로 기존의 접속된 Peer 목록을 받는다. :param request: PeerRequest :param context: :return: PeerReply """ logging.info("Trying to connect peer: " + request.peer_id) res, info = self._rs.validate_group_id(request.group_id) if res < 0: # 잘못된 입력이 들어오면 빈 list를 보내준다. return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) logging.debug("Connect Peer " + "\nPeer_id : " + request.peer_id + "\nGroup_id : " + request.group_id + "\nPeer_target : " + request.peer_target) auth = "" token = "" logging.info("CA SECURITY_MODE : " + str(self.__ca.is_secure)) if self.__ca.is_secure: logging.debug("RadioStation is secure mode") if request.token is None or request.token is "": info = "Peer Token is None" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) else: # TOKEN : "00", CERT : "01", SIGN : "02" tag = request.token[:2] data = request.token[2:] logging.debug("TOKEN TYPE : %s", tag) if tag == conf.TOKEN_TYPE_TOKEN: peer = self.__peer_manager.get_peer( request.peer_id, request.group_id) if peer is None: info = "Invalid Peer_ID[" + request.peer_id + "], Group_ID[" + request.group_id + "%s]" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) else: peer_type = request.peer_type if peer_type is loopchain_pb2.BLOCK_GENERATOR: peer_type = loopchain_pb2.PEER if self.__ca.verify_peer_token(peer_token=data, peer=peer, peer_type=peer_type): auth = peer.auth token = request.token else: info = "Invalid TOKEN" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) elif tag == conf.TOKEN_TYPE_CERT: # TODO: 인증서와 Peer_ID가 연결될 수 있는 장치가 필요(인증서 내부 정보 활용) if self.__ca.verify_certificate_der(bytes.fromhex(data)): rand_key = secrets.token_bytes(16).hex() self._rs.auth[request.peer_id] = { 'rand_key': rand_key, 'auth': data } return loopchain_pb2.PeerReply( status=message_code.Response.success, peer_list=b'', more_info=rand_key) else: info = "Invalid Peer Certificate" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) elif tag == conf.TOKEN_TYPE_SIGN: try: peer_auth = self._rs.auth[request.peer_id] rand_key = peer_auth['rand_key'] auth = peer_auth['auth'] except KeyError: info = "No Peer Info" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) logging.debug("Get Rand_key: %s, auth: %s", rand_key, auth) new_token = self.__ca.generate_peer_token( peer_sign=bytes.fromhex(data), peer_cert=bytes.fromhex(auth), peer_id=request.peer_id, peer_target=request.peer_target, group_id=request.group_id, peer_type=request.peer_type, rand_key=bytes.fromhex(rand_key), token_interval=conf.TOKEN_INTERVAL) if new_token is not None: self._rs.auth[request.peer_id] = {} token = conf.TOKEN_TYPE_TOKEN + new_token else: info = "Unknown token type(" + tag + ")" return loopchain_pb2.PeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) peer = self.__peer_manager.make_peer(request.peer_id, request.group_id, request.peer_target, PeerStatus.connected, peer_auth=auth, peer_token=token) peer_order = self.__peer_manager.add_peer_object(peer) self.__common_service.save_peer_list(self.__peer_manager) if peer_order > 0: # 접속 완료 try: peer_dump = pickle.dumps(peer) except pickle.PicklingError as e: logging.warning("Fail Peer Dump: " + str(e)) peer_dump = b'' request.peer_object = peer_dump request.peer_order = peer_order logging.debug("Connect Peer: " + str(request)) # self.__broadcast_new_peer(request) # TODO RS subsribe 를 이용하는 경우, RS 가 재시작시 peer broadcast 가 전체로 되지 않는 문제가 있다. # peer_list 를 이용하여 broadcast 하는 구조가되면 RS 혹은 Leader 에 대한 Subscribe 구조는 유효하지 않다. # 하지만 broadcast process 는 peer_list broadcast 인 경우 사용되어지지 않는다. peer_list 에서 broadcast 하는 동안 # block 되는 구조. broadcast Process 를 peer_list 를 이용한 broadcast 에서도 활용할 수 있게 하거나. # RS 혹은 Leader 가 재시작 후에 Subscribe 정보를 복원하게 하거나. # 혹은 peer_list 가 broadcast 하여도 성능상(동시성에 있어) 문제가 없는지 보증하여야 한다. TODO TODO TODO self.__peer_manager.announce_new_peer(request) logging.debug("get_IP_of_peers_in_group: " + str(self.__peer_manager.get_IP_of_peers_in_group())) try: peer_list_dump = self.__peer_manager.dump() status, reason = message_code.get_response( message_code.Response.success) # TODO 현재는 reason 을 token return 으로 사용하고 있음, 이 용도로 reason 을 사용할 때에는 token 만 담겨있어야 함 # 추후 메시지를 확장할 때 리팩토링 할 것 reason = token except pickle.PicklingError as e: logging.warning("fail peer_list dump") peer_list_dump = b'' status, reason = message_code.get_response( message_code.Response.fail) reason += " " + str(e) return loopchain_pb2.PeerReply(status=status, peer_list=peer_list_dump, more_info=reason)
def ConnectPeer(self, request, context): """RadioStation 에 접속한다. 응답으로 기존의 접속된 Peer 목록을 받는다. :param request: PeerRequest :param context: :return: PeerReply """ logging.info("Trying to connect peer: "+request.peer_id) res, info = self._rs.validate_group_id(request.group_id) if res < 0: # send null list(b'') while wrong input. return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) logging.debug("Connect Peer " + "\nPeer_id : " + request.peer_id + "\nGroup_id : " + request.group_id + "\nPeer_target : " + request.peer_target) auth = "" token = "" logging.info("CA SECURITY_MODE : " + str(self.__ca.is_secure)) if self.__ca.is_secure: logging.debug("RadioStation is secure mode") if request.token is None or request.token is "": info = "Peer Token is None" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) else: # TOKEN : "00", CERT : "01", SIGN : "02" tag = request.token[:2] data = request.token[2:] logging.debug("TOKEN TYPE : %s", tag) if tag == conf.TOKEN_TYPE_TOKEN: peer = self.__peer_manager.get_peer(request.peer_id, request.group_id) if peer is None: info = "Invalid Peer_ID[" + request.peer_id + "], Group_ID[" + request.group_id + "%s]" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) else: peer_type = request.peer_type if peer_type is loopchain_pb2.BLOCK_GENERATOR: peer_type = loopchain_pb2.PEER if self.__ca.verify_peer_token(peer_token=data, peer=peer, peer_type=peer_type): auth = peer.auth token = request.token else: info = "Invalid TOKEN" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) elif tag == conf.TOKEN_TYPE_CERT: # TODO: 인증서와 Peer_ID가 연결될 수 있는 장치가 필요(인증서 내부 정보 활용) if self.__ca.verify_certificate_der(bytes.fromhex(data)): rand_key = secrets.token_bytes(16).hex() self._rs.auth[request.peer_id] = {'rand_key': rand_key, 'auth': data} return loopchain_pb2.PeerReply(status=message_code.Response.success, peer_list=b'', more_info=rand_key) else: info = "Invalid Peer Certificate" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) elif tag == conf.TOKEN_TYPE_SIGN: try: peer_auth = self._rs.auth[request.peer_id] rand_key = peer_auth['rand_key'] auth = peer_auth['auth'] except KeyError: info = "No Peer Info" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) logging.debug("Get Rand_key: %s, auth: %s", rand_key, auth) new_token = self.__ca.generate_peer_token(peer_sign=bytes.fromhex(data), peer_cert=bytes.fromhex(auth), peer_id=request.peer_id, peer_target=request.peer_target, group_id=request.group_id, peer_type=request.peer_type, rand_key=bytes.fromhex(rand_key), token_interval=conf.TOKEN_INTERVAL) if new_token is not None: self._rs.auth[request.peer_id] = {} token = conf.TOKEN_TYPE_TOKEN + new_token else: info = "Unknown token type(" + tag + ")" return loopchain_pb2.PeerReply(status=message_code.Response.fail, peer_list=b'', more_info=info) peer = self.__peer_manager.make_peer(request.peer_id, request.group_id, request.peer_target, PeerStatus.unknown, peer_auth=auth, peer_token=token) peer_order = self.__peer_manager.add_peer_object(peer) self.__common_service.save_peer_list(self.__peer_manager) peer_list_dump = b'' status, reason = message_code.get_response(message_code.Response.fail) if peer_order > 0: try: peer_list_dump = self.__peer_manager.dump() status, reason = message_code.get_response(message_code.Response.success) # TODO 현재는 reason 을 token return 으로 사용하고 있음, 이 용도로 reason 을 사용할 때에는 token 만 담겨있어야 함 # 추후 메시지를 확장할 때 리팩토링 할 것 reason = token except pickle.PicklingError as e: logging.warning("fail peer_list dump") reason += " " + str(e) return loopchain_pb2.PeerReply( status=status, peer_list=peer_list_dump, more_info=reason )
def ConnectPeer(self, request: loopchain_pb2.ConnectPeerRequest, context): """RadioStation 에 접속한다. 응답으로 기존의 접속된 Peer 목록을 받는다. :param request: PeerRequest :param context: :return: ConnectPeerReply """ logging.info("Trying to connect peer: " + request.peer_id) res, info = ObjectManager().rs_service.validate_group_id( request.group_id) if res < 0: # send null list(b'') while wrong input. return loopchain_pb2.ConnectPeerReply( status=message_code.Response.fail, peer_list=b'', more_info=info) # TODO check peer's authorization for channel channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if not request.channel else request.channel logging.debug(f"ConnectPeer channel_name({channel_name})") # channels: list = ObjectManager().rs_service.channel_manager.authorized_channels(request.peer_id) # if channel_name not in channels: # return loopchain_pb2.ConnectPeerReply( # status=message_code.Response.fail, # peer_list=b'', # more_info=f"channel({channel_name}) is not authorized for peer_id({request.peer_id})") logging.debug("Connect Peer " + "\nPeer_id : " + request.peer_id + "\nGroup_id : " + request.group_id + "\nPeer_target : " + request.peer_target) peer = PeerInfo(request.peer_id, request.group_id, request.peer_target, PeerStatus.unknown, cert=request.cert) util.logger.spam(f"service::ConnectPeer try add_peer") peer_order = ObjectManager( ).rs_service.channel_manager.get_peer_manager(channel_name).add_peer( peer) peer_list_dump = b'' status, reason = message_code.get_response(message_code.Response.fail) if peer_order > 0: try: peer_list_dump = ObjectManager( ).rs_service.channel_manager.get_peer_manager( channel_name).dump() status, reason = message_code.get_response( message_code.Response.success) except pickle.PicklingError as e: logging.warning("fail peer_list dump") reason += " " + str(e) return loopchain_pb2.ConnectPeerReply(status=status, peer_list=peer_list_dump, channels=None, more_info=reason)