Esempio n. 1
0
    def test_add_vote_fail_before_add_peer(self):
        # GIVEN
        peer_manager = PeerManager(conf.LOOPCHAIN_DEFAULT_CHANNEL)
        self.__add_peer_to_peer_manager(peer_manager, 3)
        peer_manager.add_peer(
            PeerInfo("peerid-4",
                     "groupid-3",
                     "peerid-4_target",
                     cert=self.__cert))
        peer_manager.add_peer(
            PeerInfo("peerid-5",
                     "groupid-3",
                     "peerid-5_target",
                     cert=self.__cert))

        vote = Vote("block_hash", peer_manager)
        logging.debug("votes: " + str(vote.votes))

        # WHEN
        vote.add_vote("groupid-1", "peerid-1", None)
        vote.add_vote("groupid-3", "peerid-4", None)
        ret1 = vote.add_vote("groupid-4", "peerid-1", None)
        ret2 = vote.add_vote("groupid-1", "peerid-9", None)
        self.assertFalse(ret1)
        self.assertFalse(ret2)

        # THEN
        ret = vote.get_result_detail("block_hash", 0.51)
        self.assertEqual(ret[5], 5)
Esempio n. 2
0
    def test_fail_vote(self):
        # GIVEN
        peer_manager = PeerManager(conf.LOOPCHAIN_DEFAULT_CHANNEL)
        self.__add_peer_to_peer_manager(peer_manager, 3)
        peer_manager.add_peer(
            PeerInfo("peerid-4",
                     "groupid-3",
                     "peerid-4_target",
                     cert=self.__cert))
        peer_manager.add_peer(
            PeerInfo("peerid-5",
                     "groupid-3",
                     "peerid-5_target",
                     cert=self.__cert))

        vote = Vote("block_hash", peer_manager)
        logging.debug("votes: " + str(vote.votes))

        # WHEN
        vote.add_vote("groupid-1", "peerid-1", conf.TEST_FAIL_VOTE_SIGN)
        vote.add_vote("groupid-3", "peerid-4", conf.TEST_FAIL_VOTE_SIGN)
        vote.add_vote("groupid-3", "peerid-5", conf.TEST_FAIL_VOTE_SIGN)
        vote.get_result("block_hash", 0.51)

        # THEN
        self.assertTrue(vote.is_failed_vote("block_hash", 0.51))
Esempio n. 3
0
    def announce_new_peer(self, peer_info_dumped, peer_target) -> None:
        try:
            peer_info = PeerInfo.load(peer_info_dumped)
        except Exception as e:
            traceback.print_exc()
            logging.error(
                f"Invalid peer info. peer_target={peer_target}, exception={e}")
            return

        logging.debug("Add New Peer: " + str(peer_info.peer_id))

        peer_manager = self._channel_service.peer_manager
        peer_manager.add_peer(peer_info)
        # broadcast the new peer to the others for adding an audience
        self._channel_service.broadcast_scheduler.schedule_job(
            BroadcastCommand.SUBSCRIBE, peer_target)

        logging.debug("Try save peer list...")
        # self._channel_service.save_peer_manager(peer_manager)
        self._channel_service.show_peers()

        if conf.CONSENSUS_ALGORITHM == conf.ConsensusAlgorithm.lft:
            quorum, complain_quorum = peer_manager.get_quorum()
            self._channel_service.consensus.set_quorum(
                quorum=quorum, complain_quorum=complain_quorum)
Esempio n. 4
0
    def test_add_vote(self):
        # GIVEN
        peer_manager = PeerManager(conf.LOOPCHAIN_DEFAULT_CHANNEL)
        self.__add_peer_to_peer_manager(peer_manager, 3)
        peer_manager.add_peer(PeerInfo("peerid-4", "groupid-3", "peerid-4_target"))
        peer_manager.add_peer(PeerInfo("peerid-5", "groupid-3", "peerid-5_target"))

        vote = Vote("block_hash", peer_manager)
        logging.debug("votes: " + str(vote.votes))

        # WHEN
        vote.add_vote("peerid-1", None)
        self.assertFalse(vote.get_result("block_hash", 0.51))

        # THEN
        vote.add_vote("peerid-2", None)
        self.assertTrue(vote.get_result("block_hash", 0.51))
Esempio n. 5
0
 def __add_peer_to_peer_manager(self, peer_manager: PeerManager,
                                number_of_peer):
     for i in range(1, number_of_peer + 1):
         number = str(i)
         peer_data = PeerInfo("peerid-" + number,
                              "groupid-" + number,
                              "peerid-" + number + "_target",
                              cert=self.__cert)
         peer_manager.add_peer(peer_data)
Esempio n. 6
0
 def get_leader_object(self):
     mock_info = PeerInfo(peer_id="peer_id",
                          group_id='a',
                          target="192.0.0.1:1234",
                          status=PeerStatus.unknown,
                          cert=self.__peer_auth.peer_cert,
                          order=0)
     mock_peer_object = PeerObject(list(conf.CHANNEL_OPTION)[0], mock_info)
     return mock_peer_object
Esempio n. 7
0
    def add_peer(self, peer_info: Union[PeerInfo, dict]):
        """add_peer to peer_manager

        :param peer_info: PeerInfo, dict
        :return: create_peer_order
        """

        if isinstance(peer_info, dict):
            peer_info = PeerInfo(peer_info["id"], peer_info["id"], peer_info["peer_target"], order=peer_info["order"])

        logging.debug(f"add peer id: {peer_info.peer_id}")

        # If exist same peer_target in peer_list, delete exist one.
        # this is temporary rule that will be argued.
        # if peer_info.peer_id not in self.peer_list[conf.ALL_GROUP_ID].keys():
        #     exist_peer = self.__get_peer_by_target(peer_info.target)
        #     if exist_peer is not None:
        #         self.remove_peer(exist_peer.peer_id, exist_peer.group_id)

        self.__init_peer_group(peer_info.group_id)

        util.logger.spam(f"peer_manager::add_peer try make PeerObject")
        peer_object = PeerObject(self.__channel_name, peer_info)

        # add_peer logic must be atomic
        with self.__add_peer_lock:
            if peer_info.order <= 0:
                if peer_info.peer_id in self.peer_list[peer_info.group_id]:
                    peer_info.order = self.peer_list[peer_info.group_id][peer_info.peer_id].order
                else:
                    peer_info.order = self.__make_peer_order(peer_info)

            logging.debug(f"new peer order {peer_info.peer_id} : {peer_info.order}")

            # set to leader peer
            if (self.peer_leader[peer_info.group_id] == 0) or (len(self.peer_list[peer_info.group_id]) == 0):
                logging.debug("Set Group Leader Peer: " + str(peer_info.order))
                self.peer_leader[peer_info.group_id] = peer_info.order

            if (self.peer_leader[conf.ALL_GROUP_ID] == 0) or (len(self.peer_list[conf.ALL_GROUP_ID]) == 0):
                logging.debug("Set ALL Leader Peer: " + str(peer_info.order))
                self.peer_leader[conf.ALL_GROUP_ID] = peer_info.order

            self.peer_list[peer_info.group_id][peer_info.peer_id] = peer_info
            self.peer_list[conf.ALL_GROUP_ID][peer_info.peer_id] = peer_info
            self.peer_order_list[peer_info.group_id][peer_info.order] = peer_info.peer_id
            self.peer_order_list[conf.ALL_GROUP_ID][peer_info.order] = peer_info.peer_id
            self.__peer_object_list[peer_info.group_id][peer_info.peer_id] = peer_object
            self.__peer_object_list[conf.ALL_GROUP_ID][peer_info.peer_id] = peer_object

        return peer_info.order
Esempio n. 8
0
    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
Esempio n. 9
0
    def setUp(self):
        test_util.print_testname(self._testMethodName)
        self.__peer_auth = test_util.create_peer_auth()

        peer_service_mock = Mock()
        peer_service_mock.peer_manager = Mock()
        mock_info = PeerInfo(peer_id=self.__peer_id,
                             group_id='a',
                             target="192.0.0.1:1234",
                             status=PeerStatus.unknown,
                             cert=self.__peer_auth.get_public_der(),
                             order=0)
        mock_peer_object = PeerObject(mock_info)

        def get_leader_object():
            return mock_peer_object

        peer_service_mock.peer_manager.get_leader_object = get_leader_object
        ObjectManager().peer_service = peer_service_mock
Esempio n. 10
0
    def deserialize(peer_list_data_serialized: dict) -> 'PeerListData':
        peer_info_list = dict()
        for group_id, peer_info_group_serialized in peer_list_data_serialized['peer_info_list'].items():
            group = dict()
            for peer_id, peer_info_serialized in peer_info_group_serialized.items():
                group[peer_id] = PeerInfo.deserialize(peer_info_serialized)
            peer_info_list[group_id] = group

        peer_order_list = dict()
        for group_id, order_list in peer_list_data_serialized['peer_order_list'].items():
            converted_order_list = dict()
            for order, peer_id in order_list.items():
                converted_order_list[int(order)] = peer_id
            peer_order_list[group_id] = converted_order_list

        peer_list_data = PeerListData()
        peer_list_data.__peer_info_list = peer_info_list
        peer_list_data.__peer_leader = peer_list_data_serialized['peer_leader']
        peer_list_data.__peer_order_list = peer_order_list
        return peer_list_data
Esempio n. 11
0
    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)
Esempio n. 12
0
    async def get(self, request, request_type):
        # args = ServerComponents().parser.parse_args()
        args = request.raw_args
        channel = get_channel_name_from_args(args)
        logging.debug(f'channel name : {channel}')
        if request_type == self.__REQUEST_TYPE['PEER_LIST']:
            grpc_response = ServerComponents().get_peer_list(channel)

            peer_manager = PeerManager(channel)
            peer_list_data = PeerListData.load(grpc_response.peer_list)
            peer_manager.set_peer_list(peer_list_data)

            all_peer_list = []
            connected_peer_list = []

            if peer_manager.peer_list:
                leader_peer_id = ""

                # for set peer_type info to peer
                leader_peer = peer_manager.get_leader_peer(conf.ALL_GROUP_ID,
                                                           is_peer=False)
                if leader_peer is not None:
                    leader_peer_id = leader_peer.peer_id

                for peer_id in peer_manager.peer_list[conf.ALL_GROUP_ID]:
                    peer_each: PeerInfo = peer_manager.peer_list[
                        conf.ALL_GROUP_ID][peer_id]
                    peer_data = peer_each.serialize()

                    if peer_each.peer_id == leader_peer_id:
                        peer_data['peer_type'] = loopchain_pb2.BLOCK_GENERATOR
                    else:
                        peer_data['peer_type'] = loopchain_pb2.PEER

                    all_peer_list.append(peer_data)

                    if peer_each.status == PeerStatus.connected:
                        connected_peer_list.append(peer_data)

            json_data = {
                'registered_peer_count': len(all_peer_list),
                'connected_peer_count': len(connected_peer_list),
                'registered_peer_list': all_peer_list,
                'connected_peer_list': connected_peer_list
            }
            result = {
                'response_code': message_code.Response.success,
                'data': json_data
            }

        elif request_type == self.__REQUEST_TYPE['PEER_STATUS_LIST']:
            grpc_response = ServerComponents().get_peer_list(channel)

            peer_manager = PeerManager(channel)
            peer_list_data = PeerListData.load(grpc_response.peer_list)
            peer_manager.set_peer_list(peer_list_data)

            registered_peer_count = 0
            connected_peer_count = 0
            all_peer_list = []

            if peer_manager.peer_list:
                async_futures: List[grpc.Future] = []
                for peer_id in peer_manager.peer_list[conf.ALL_GROUP_ID]:
                    async_future = ServerComponents().get_peer_status_async(
                        peer_id, conf.ALL_GROUP_ID, channel)
                    async_futures.append(async_future)

                if async_futures:
                    futures.as_completed(async_futures)

                for async_future, peer_id in zip(
                        async_futures,
                        peer_manager.peer_list[conf.ALL_GROUP_ID]):
                    if async_future.exception():
                        logging.warning(
                            f'RequestType({request_type}), exception({async_future.exception()})'
                        )
                        continue

                    grpc_response = async_future.result()
                    if grpc_response is not None and grpc_response.status != "":
                        peer_each = peer_manager.peer_list[
                            conf.ALL_GROUP_ID][peer_id]
                        status_json = json.loads(grpc_response.status)
                        status_json["order"] = peer_each.order
                        all_peer_list.append(status_json)

                registered_peer_count = peer_manager.get_peer_count()
                connected_peer_count = peer_manager.get_connected_peer_count()

            json_data = {
                'registered_peer_count': registered_peer_count,
                'connected_peer_count': connected_peer_count,
                'peer_status_list': all_peer_list
            }
            result = {
                'response_code': message_code.Response.success,
                'data': json_data
            }

        elif request_type == self.__REQUEST_TYPE['LEADER_PEER']:
            grpc_response = ServerComponents().get_leader_peer(channel)

            result = dict()
            result['response_code'] = grpc_response.code

            if grpc_response.code == message_code.Response.success:
                peer_info = PeerInfo.load(grpc_response.object)
                result['data'] = peer_info.serialize()
            else:
                result['message'] = message_code.get_response_msg(
                    grpc_response.code)

        elif request_type == self.__REQUEST_TYPE['PEER_STATUS']:
            peer_id = args['peer_id']
            group_id = args['group_id']

            if peer_id is None or group_id is None:
                return self.__abort_if_arg_isnt_enough('peer_id, group_id')

            # logging.debug(f"try get_peer_status peer_id({peer_id}), group_id({group_id})")
            grpc_response = ServerComponents().get_peer_status(
                args['peer_id'], args['group_id'], channel)
            result = json.loads(grpc_response.status)

        else:
            return ServerComponents().abort_if_url_doesnt_exist(
                request_type, self.__REQUEST_TYPE)

        return response.json(result)
Esempio n. 13
0
    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)