Exemple #1
0
    def update_sub_services_properties(self, **properties):
        logging.info(f"properties {properties}")
        stub = StubCollection().channel_tx_creator_stubs[
            ChannelProperty().name]
        asyncio.run_coroutine_threadsafe(
            stub.async_task().update_properties(properties),
            self.__loop_for_sub_services)

        stub = StubCollection().channel_tx_receiver_stubs[
            ChannelProperty().name]
        asyncio.run_coroutine_threadsafe(
            stub.async_task().update_properties(properties),
            self.__loop_for_sub_services)
Exemple #2
0
    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 = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_tx(request.tx_hash),
            self.peer_service.inner_service.loop).result()

        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)
Exemple #3
0
    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]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_tx_by_address(address, index),
            self.peer_service.inner_service.loop)
        tx_list, next_index = future.result()
        tx_list_dumped = json.dumps(tx_list).encode(
            encoding=conf.PEER_DATA_ENCODING)

        return loopchain_pb2.Message(code=message_code.Response.success,
                                     meta=str(next_index),
                                     object=tx_list_dumped)
    def GetBlock(self, request, context):
        """Block 정보를 조회한다.

        :param request: loopchain.proto 의 GetBlockRequest 참고
         request.block_hash: 조회할 block 의 hash 값, "" 로 조회하면 마지막 block 의 hash 값을 리턴한다.
         request.block_data_filter: block 정보 중 조회하고 싶은 key 값 목록 "key1, key2, key3" 형식의 string
         request.tx_data_filter: block 에 포함된 transaction(tx) 중 조회하고 싶은 key 값 목록
        "key1, key2, key3" 형식의 string
        :param context:
        :return: loopchain.proto 의 GetBlockReply 참고,
        block_hash, block 정보 json, block 에 포함된 tx 정보의 json 리스트를 받는다.
        포함되는 정보는 param 의 filter 에 따른다.
        """

        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel

        channel_stub = StubCollection().channel_stubs[channel_name]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_block(
                block_height=request.block_height,
                block_hash=request.block_hash,
                block_data_filter=request.block_data_filter,
                tx_data_filter=request.tx_data_filter
            ), self.peer_service.inner_service.loop
        )
        response_code, block_hash, confirm_info, block_data_json, tx_data_json_list = future.result()

        return loopchain_pb2.GetBlockReply(response_code=response_code,
                                           block_hash=block_hash,
                                           block_data_json=block_data_json,
                                           confirm_info=confirm_info,
                                           tx_data_json=tx_data_json_list)
    def UnSubscribe(self, request, context):
        """BlockGenerator 의 broadcast 채널에서 Peer 를 제외한다.

        :param request:
        :param context:
        :return:
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel

        channel_stub = StubCollection().channel_stubs[channel_name]
        peer_list = [target['peer_target'] for target in self.peer_service.channel_infos[channel_name]["peers"]]

        if (request.peer_target in peer_list and conf.ENABLE_CHANNEL_AUTH) or \
                (request.node_type == loopchain_pb2.CommunityNode and not conf.ENABLE_CHANNEL_AUTH):
            asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().remove_audience(peer_target=request.peer_target),
                self.peer_service.inner_service.loop
            )
            util.logger.spam(f"peer_outer_service::Unsubscribe remove_audience target({request.peer_target}) "
                             f"in channel({request.channel})")
        else:
            logging.error(f"This target({request.peer_target}), {request.node_type} failed to unsubscribe.")
            return loopchain_pb2.CommonReply(response_code=message_code.get_response_code(message_code.Response.fail),
                                             message=message_code.get_response_msg("Unknown type peer"))

        return loopchain_pb2.CommonReply(response_code=message_code.get_response_code(message_code.Response.success),
                                         message=message_code.get_response_msg(message_code.Response.success))
Exemple #6
0
    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 ComplainLeader(self, request: ComplainLeaderRequest, context):
        channel = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        utils.logger.info(f"ComplainLeader {request.complain_vote}")

        channel_stub = StubCollection().channel_stubs[channel]
        asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().complain_leader(vote_dumped=request.complain_vote),
            self.peer_service.inner_service.loop
        )

        return loopchain_pb2.CommonReply(response_code=message_code.Response.success, message="success")
    def VoteUnconfirmedBlock(self, request, context):
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel

        utils.logger.debug(f"VoteUnconfirmedBlock vote({request.vote})")

        channel_stub = StubCollection().channel_stubs[channel_name]
        asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().vote_unconfirmed_block(request.vote),
            self.peer_service.inner_service.loop
        )
        return loopchain_pb2.CommonReply(response_code=message_code.Response.success, message="success")
    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]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_peer_list(),
            self.peer_service.inner_service.loop
        )
        all_group_peer_list_str, peer_list_str = future.result()

        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 AnnounceUnconfirmedBlock(self, request, context):
        """수집된 tx 로 생성한 Block 을 각 peer 에 전송하여 검증을 요청한다.

        :param request:
        :param context:
        :return:
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        util.logger.debug(f"peer_outer_service::AnnounceUnconfirmedBlock channel({channel_name})")

        channel_stub = StubCollection().channel_stubs[channel_name]
        asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().announce_unconfirmed_block(request.block),
            self.peer_service.inner_service.loop
        )
        return loopchain_pb2.CommonReply(response_code=message_code.Response.success, message="success")
    def __get_status_from_cache(self, channel: str):
        if channel in self.peer_service.status_cache:
            if channel in self.__status_cache_update_time:
                if util.datetime_diff_in_mins(
                        self.__status_cache_update_time[channel]) \
                        > conf.ALLOW_STATUS_CACHE_LAST_UPDATE_IN_MINUTES:
                    return None
            status_data = self.peer_service.status_cache[channel]
        else:
            channel_stub = StubCollection().channel_stubs[channel]
            status_data = asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().get_status(),
                self.peer_service.inner_service.loop
            ).result()
            self.peer_service.status_cache[channel] = status_data

        return status_data
Exemple #12
0
    def __get_status_cache(self, channel_name, time_in_seconds):
        utils.logger.spam(f"__get_status_cache in seconds({time_in_seconds})")

        try:
            channel_stub = StubCollection().channel_stubs[channel_name]
        except KeyError:
            raise ChannelStatusError(f"Invalid channel({channel_name})")

        if self.__status_cache is None:
            self.__status_cache = channel_stub.sync_task().get_status()
        else:
            future = asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().get_status(),
                self.peer_service.inner_service.loop)
            future.add_done_callback(self.__set_status_cache)

        return self.__status_cache
    def GetPrecommitBlock(self, request, context):
        """Return the precommit bock.

        :param request:
        :param context:
        :return: loopchain.proto 의 PrecommitBlockReply 참고,
        """

        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        channel_stub = StubCollection().channel_stubs[channel_name]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_precommit_block(last_block_height=request.last_block_height),
            self.peer_service.inner_service.loop
        )
        response_code, response_message, block = future.result()

        return loopchain_pb2.PrecommitBlockReply(
            response_code=response_code, response_message=response_message, block=block)
    def GetInvokeResult(self, request, context):
        """get invoke result by tx_hash

        :param request: request.tx_hash = tx_hash
        :param context:
        :return: verify result
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        logging.debug(f"peer_outer_service:GetInvokeResult in channel({channel_name})")

        channel_stub = StubCollection().channel_stubs[channel_name]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().get_invoke_result(request.tx_hash),
            self.peer_service.inner_service.loop
        )
        response_code, result = future.result()

        return loopchain_pb2.GetInvokeResultReply(response_code=response_code, result=result)
    def ComplainLeader(self, request: ComplainLeaderRequest, context):
        channel = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        util.logger.notice(f"ComplainLeader "
                           f"height({request.block_height}) complained_peer({request.complained_leader_id})")

        channel_stub = StubCollection().channel_stubs[channel]

        asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().complain_leader(
                complained_leader_id=request.complained_leader_id,
                new_leader_id=request.new_leader_id,
                block_height=request.block_height,
                peer_id=request.peer_id,
                group_id=request.group_id
            ),
            self.peer_service.inner_service.loop
        )

        return loopchain_pb2.CommonReply(response_code=message_code.Response.success, message="success")
    def AnnounceUnconfirmedBlock(self, request, context):
        """Send the UnconfirmedBlock includes collected transactions to reps and request to verify it.

        :param request:
        :param context:
        :return:
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        channel_stub = StubCollection().channel_stubs[channel_name]

        try:
            round_ = request.round_
        except AttributeError:
            round_ = 0

        asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().announce_unconfirmed_block(request.block, round_),
            self.peer_service.inner_service.loop
        )
        return loopchain_pb2.CommonReply(response_code=message_code.Response.success, message="success")
    def CreateTx(self, request, context):
        """make tx by client request and broadcast it to the network

        :param request:
        :param context:
        :return:
        """
        channel_name = request.channel or conf.LOOPCHAIN_DEFAULT_CHANNEL
        logging.info(f"peer_outer_service::CreateTx request({request.data}), channel({channel_name})")

        channel_stub = StubCollection().channel_stubs[channel_name]
        result_hash = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().create_tx(request.data),
            self.peer_service.inner_service.loop
        ).result()

        return loopchain_pb2.CreateTxReply(
            response_code=message_code.Response.success,
            tx_hash=result_hash,
            more_info='')
    def AnnounceNewPeer(self, request, context):
        """RadioStation에서 Broadcasting 으로 신규 피어정보를 받아온다

        :param request: PeerRequest
        :param context:
        :return:
        """
        # RadioStation To Peer
        # prevent to show certificate content
        # logging.info('Here Comes new peer: ' + str(request))
        channel = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        logging.debug(f"peer outer service::AnnounceNewPeer channel({channel})")

        if request.peer_object:
            channel_stub = StubCollection().channel_stubs[channel]
            asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().announce_new_peer(request.peer_object, request.peer_target),
                self.peer_service.inner_service.loop
            )

        return loopchain_pb2.CommonReply(response_code=0, message="success")
    def BlockSync(self, request, context):
        # Peer To Peer
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        logging.info(f"BlockSync request hash({request.block_hash}) "
                     f"request height({request.block_height}) channel({channel_name})")

        channel_stub = StubCollection().channel_stubs[channel_name]
        future = asyncio.run_coroutine_threadsafe(
            channel_stub.async_task().block_sync(request.block_hash, request.block_height),
            self.peer_service.inner_service.loop
        )
        response_code, block_height, max_block_height, unconfirmed_block_height, confirm_info, block_dumped = \
            future.result()

        return loopchain_pb2.BlockSyncReply(
            response_code=response_code,
            block_height=block_height,
            max_block_height=max_block_height,
            confirm_info=confirm_info,
            block=block_dumped,
            unconfirmed_block_height=unconfirmed_block_height)
    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:
            for channel_name in self.peer_service.channel_infos:
                channel_stub = StubCollection().channel_stubs[channel_name]
                asyncio.run_coroutine_threadsafe(channel_stub.async_task().stop(), self.peer_service.inner_service.loop)

            self.peer_service.p2p_server_stop()

        except Exception as e:
            logging.debug("Score Service Already stop by other reason. %s", e)

        return loopchain_pb2.StopReply(status="0")
    def __get_status_cache(self, channel_name, time_in_seconds):
        """Cache status data.

        :param channel_name:
        :param time_in_seconds: An essential parameter for the `LRU cache` even if not used.

        :return:
        """
        try:
            channel_stub = StubCollection().channel_stubs[channel_name]
        except KeyError:
            raise ChannelStatusError(f"Invalid channel({channel_name})")

        if self.__status_cache is None:
            self.__status_cache = channel_stub.sync_task().get_status()
        else:
            future = asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().get_status(),
                self.peer_service.inner_service.loop)
            future.add_done_callback(self.__set_status_cache)

        return self.__status_cache
    def Subscribe(self, request, context):
        """BlockGenerator 가 broadcast(unconfirmed or confirmed block) 하는 채널에
        Peer 를 등록한다.

        :param request:
        :param context:
        :return:
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        if not request.peer_id or not request.peer_target:
            return loopchain_pb2.CommonReply(
                response_code=message_code.get_response_code(message_code.Response.fail_wrong_subscribe_info),
                message=message_code.get_response_msg(message_code.Response.fail_wrong_subscribe_info)
            )

        try:
            channel_stub = StubCollection().channel_stubs[channel_name]
        except KeyError:
            return loopchain_pb2.CommonReply(response_code=message_code.get_response_code(message_code.Response.fail),
                                             message=f"There is no channel_stubs for channel({channel_name}).")

        peer_list = [target['peer_target'] for target in self.peer_service.channel_infos[channel_name]["peers"]]

        if (request.peer_target in peer_list and conf.ENABLE_CHANNEL_AUTH) or \
                (request.node_type == loopchain_pb2.CommunityNode and not conf.ENABLE_CHANNEL_AUTH):
            asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().add_audience(peer_target=request.peer_target),
                self.peer_service.inner_service.loop
            )
            util.logger.debug(f"peer_outer_service::Subscribe add_audience "
                              f"target({request.peer_target}) in channel({request.channel}), "
                              f"order({request.peer_order})")
        else:
            logging.error(f"This target({request.peer_target}, {request.node_type}) failed to subscribe.")
            return loopchain_pb2.CommonReply(response_code=message_code.get_response_code(message_code.Response.fail),
                                             message=message_code.get_response_msg("Unknown type peer"))

        return loopchain_pb2.CommonReply(response_code=message_code.get_response_code(message_code.Response.success),
                                         message=message_code.get_response_msg(message_code.Response.success))
    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)
Exemple #24
0
    def GetStatus(self, request, context):
        """Peer 의 현재 상태를 요청한다.

        :param request:
        :param context:
        :return:
        """
        channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL if request.channel == '' else request.channel
        logging.debug("Peer GetStatus : %s", request)

        try:
            channel_stub = StubCollection().channel_stubs[channel_name]

            callback = partial(self.__status_update, channel_name)
            future = asyncio.run_coroutine_threadsafe(
                channel_stub.async_task().get_status(),
                self.peer_service.inner_service.loop)
            future.add_done_callback(callback)

        except BaseException as e:
            logging.error(f"Peer GetStatus Exception : {e}")

        status_data = self.__get_status_data(channel_name)
        if status_data is None:
            raise ChannelStatusError(f"Fail get status data from channel({channel_name})")

        status_data = copy.deepcopy(status_data)

        stubs = {
            "peer": StubCollection().peer_stub,
            "channel": StubCollection().channel_stubs.get(channel_name),
            "score":
                StubCollection().icon_score_stubs.get(channel_name)
                if util.channel_use_icx(channel_name) else
                StubCollection().score_stubs.get(channel_name)
        }

        mq_status_data = {}
        mq_down = False
        for key, stub in stubs.items():
            message_count = -1
            message_error = None
            try:
                mq_info = stub.sync_info().queue_info()
                message_count = mq_info.method.message_count
            except AttributeError:
                message_error = "Stub is not initialized."
            except Exception as e:
                message_error = f"{type(e).__name__}, {e}"

            mq_status_data[key] = {}
            mq_status_data[key]["message_count"] = message_count
            if message_error:
                mq_status_data[key]["error"] = message_error
                mq_down = True

        status_data["mq"] = mq_status_data
        if mq_down:
            reason = status_code.get_status_reason(status_code.Service.mq_down)
            status_data["status"] = "Service is offline: " + reason

        return loopchain_pb2.StatusReply(
            status=json.dumps(status_data),
            block_height=status_data["block_height"],
            total_tx=status_data["total_tx"],
            is_leader_complaining=status_data['leader_complaint'],
            peer_id=status_data['peer_id'])