Esempio n. 1
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. 2
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. 3
0
class Epoch:
    COMPLAIN_VOTE_HASH = "complain_vote_hash_for_reuse_Vote_class"

    def __init__(self, height: int, leader_id=None):
        util.logger.notice(
            f"New Epoch Start height({height}) leader_id({leader_id})")
        self.height = height
        self.leader_id = leader_id

        # TODO using Epoch in BlockManager instead using candidate_blocks directly.
        # But now! only collect leader complain votes.
        self.__candidate_blocks = None
        self.__complain_vote = Vote(
            Epoch.COMPLAIN_VOTE_HASH,
            ObjectManager().channel_service.peer_manager)

    @staticmethod
    def new_epoch(height: int, leader_id=None):
        leader_id = leader_id or ObjectManager(
        ).channel_service.block_manager.epoch.leader_id
        return Epoch(height, leader_id)

    def set_epoch_leader(self, leader_id):
        util.logger.notice(
            f"Set Epoch leader height({self.height}) leader_id({leader_id})")
        self.leader_id = leader_id

    def add_complain(self, complained_leader_id, new_leader_id, block_height,
                     peer_id, group_id):
        util.logger.notice(
            f"add_complain complain_leader_id({complained_leader_id}), "
            f"new_leader_id({new_leader_id}), "
            f"block_height({block_height}), "
            f"peer_id({peer_id})")
        self.__complain_vote.add_vote(group_id, peer_id, new_leader_id)

    def complain_result(self) -> str or None:
        """return new leader id when complete complain leader.

        :return: new leader id or None
        """
        vote_result = self.__complain_vote.get_result(
            Epoch.COMPLAIN_VOTE_HASH, conf.LEADER_COMPLAIN_RATIO)
        util.logger.notice(f"complain_result vote_result({vote_result})")

        return vote_result
Esempio n. 4
0
class Epoch:
    COMPLAIN_VOTE_HASH = "complain_vote_hash_for_reuse_Vote_class"

    def __init__(self, block_manager, leader_id=None):
        if block_manager.get_blockchain().last_block:
            self.height = block_manager.get_blockchain().last_block.header.height + 1
        else:
            self.height = 1
        self.leader_id = leader_id
        self.__block_manager = block_manager
        self.__blockchain = self.__block_manager.get_blockchain()
        util.logger.debug(f"New Epoch Start height({self.height }) leader_id({leader_id})")

        # TODO using Epoch in BlockManager instead using candidate_blocks directly.
        # But now! only collect leader complain votes.
        self.__candidate_blocks = None
        self.__complain_vote = Vote(Epoch.COMPLAIN_VOTE_HASH, ObjectManager().channel_service.peer_manager)
        self.complained_result = None

    @staticmethod
    def new_epoch(leader_id=None):
        block_manager = ObjectManager().channel_service.block_manager
        leader_id = leader_id or ObjectManager().channel_service.block_manager.epoch.leader_id
        return Epoch(block_manager, leader_id)

    def set_epoch_leader(self, leader_id, complained=False):
        util.logger.debug(f"Set Epoch leader height({self.height}) leader_id({leader_id})")
        self.leader_id = leader_id
        if complained and leader_id == ChannelProperty().peer_id:
            self.complained_result = self.complain_result()
        else:
            self.complained_result = None
        self.__complain_vote = Vote(Epoch.COMPLAIN_VOTE_HASH, ObjectManager().channel_service.peer_manager)

    def add_complain(self, complained_leader_id, new_leader_id, block_height, peer_id, group_id):
        util.logger.debug(f"add_complain complain_leader_id({complained_leader_id}), "
                          f"new_leader_id({new_leader_id}), "
                          f"block_height({block_height}), "
                          f"peer_id({peer_id})")
        self.__complain_vote.add_vote(peer_id, new_leader_id)

    def complain_result(self) -> str:
        """return new leader id when complete complain leader.

        :return: new leader id or None
        """
        vote_result = self.__complain_vote.get_result(Epoch.COMPLAIN_VOTE_HASH, conf.LEADER_COMPLAIN_RATIO)
        util.logger.debug(f"complain_result vote_result({vote_result})")
        return vote_result

    def pop_complained_candidate_leader(self):
        voters = self.__complain_vote.get_voters()
        if ChannelProperty().peer_id not in voters:
            # Processing to complain leader
            return None

        # Complained by myself but not completed.

        # I want to pop candidate leader with this method but this method can't pop, just get but will be pop
        # self.__complain_vote = Vote(Epoch.COMPLAIN_VOTE_HASH, ObjectManager().channel_service.peer_manager)

        peer_order_list = ObjectManager().channel_service.peer_manager.peer_order_list[conf.ALL_GROUP_ID]
        peer_order_len = len(peer_order_list)
        start_order = 1  # ObjectManager().channel_service.peer_manager.get_peer(self.leader_id).order

        for i in range(peer_order_len):
            index = (i + start_order) % (peer_order_len + 1)

            try:
                peer_id = peer_order_list[index]
            except KeyError:
                peer_id = None

            if peer_id in voters:
                util.logger.info(f"set epoch new leader id({peer_id}), voters length={len(voters)}")
                return peer_id

        return None

    def _check_unconfirmed_block(self):
        blockchain = self.__block_manager.get_blockchain()
        # util.logger.debug(f"-------------------_check_unconfirmed_block, "
        #                    f"candidate_blocks({len(self._block_manager.candidate_blocks.blocks)})")
        if blockchain.last_unconfirmed_block:
            vote = self.__block_manager.candidate_blocks.get_vote(blockchain.last_unconfirmed_block.header.hash)
            # util.logger.debug(f"-------------------_check_unconfirmed_block, "
            #                    f"last_unconfirmed_block({self._blockchain.last_unconfirmed_block.header.hash}), "
            #                    f"vote({vote.votes})")
            vote_result = vote.get_result(blockchain.last_unconfirmed_block.header.hash.hex(), conf.VOTING_RATIO)
            if not vote_result:
                util.logger.debug(f"last_unconfirmed_block({blockchain.last_unconfirmed_block.header.hash}), "
                                  f"vote result({vote_result})")

    def __add_tx_to_block(self, block_builder):
        tx_queue = self.__block_manager.get_tx_queue()

        block_tx_size = 0
        tx_versioner = self.__blockchain.tx_versioner
        while tx_queue:
            if block_tx_size >= conf.MAX_TX_SIZE_IN_BLOCK:
                logging.debug(f"consensus_base total size({block_builder.size()}) "
                              f"count({len(block_builder.transactions)}) "
                              f"_txQueue size ({len(tx_queue)})")
                break

            tx: 'Transaction' = tx_queue.get_item_in_status(
                TransactionStatusInQueue.normal,
                TransactionStatusInQueue.added_to_block
            )
            if tx is None:
                break

            tv = TransactionVerifier.new(tx.version, tx_versioner)

            try:
                tv.verify(tx, self.__blockchain)
            except Exception as e:
                logging.warning(f"tx hash invalid.\n"
                                f"tx: {tx}\n"
                                f"exception: {e}")
                traceback.print_exc()
            else:
                block_builder.transactions[tx.hash] = tx
                block_tx_size += tx.size(tx_versioner)

    def makeup_block(self, complained_result: str):
        # self._check_unconfirmed_block(
        last_block = self.__blockchain.last_unconfirmed_block or self.__blockchain.last_block
        block_height = last_block.header.height + 1
        block_version = self.__blockchain.block_versioner.get_version(block_height)
        block_builder = BlockBuilder.new(block_version, self.__blockchain.tx_versioner)
        if not complained_result:
            self.__add_tx_to_block(block_builder)

        return block_builder
Esempio n. 5
0
class Epoch:
    COMPLAIN_VOTE_HASH = "complain_vote_hash_for_reuse_Vote_class"

    def __init__(self, block_manager, leader_id=None):
        if block_manager.get_blockchain().last_block:
            self.height = block_manager.get_blockchain(
            ).last_block.header.height + 1
        else:
            self.height = 1
        self.leader_id = leader_id
        self.prev_leader_id = None
        self.__block_manager = block_manager
        self.__blockchain = self.__block_manager.get_blockchain()
        util.logger.debug(
            f"New Epoch Start height({self.height }) leader_id({leader_id})")

        # TODO using Epoch in BlockManager instead using candidate_blocks directly.
        # But now! only collect leader complain votes.
        self.__candidate_blocks = None
        self.__complain_vote = Vote(
            Epoch.COMPLAIN_VOTE_HASH,
            ObjectManager().channel_service.peer_manager)

    @staticmethod
    def new_epoch(leader_id=None):
        block_manager = ObjectManager().channel_service.block_manager
        leader_id = leader_id or ObjectManager(
        ).channel_service.block_manager.epoch.leader_id
        return Epoch(block_manager, leader_id)

    def set_epoch_leader(self, leader_id):
        util.logger.debug(
            f"Set Epoch leader height({self.height}) leader_id({leader_id})")
        self.leader_id = leader_id
        self.__complain_vote = Vote(
            Epoch.COMPLAIN_VOTE_HASH,
            ObjectManager().channel_service.peer_manager)

    def add_complain(self, complained_leader_id, new_leader_id, block_height,
                     peer_id, group_id):
        util.logger.debug(
            f"add_complain complain_leader_id({complained_leader_id}), "
            f"new_leader_id({new_leader_id}), "
            f"block_height({block_height}), "
            f"peer_id({peer_id})")
        self.__complain_vote.add_vote(group_id, peer_id, new_leader_id)

    def complain_result(self) -> str:
        """return new leader id when complete complain leader.

        :return: new leader id or None
        """
        vote_result = self.__complain_vote.get_result(
            Epoch.COMPLAIN_VOTE_HASH, conf.LEADER_COMPLAIN_RATIO)
        util.logger.debug(f"complain_result vote_result({vote_result})")

        return vote_result

    def _check_unconfirmed_block(self):
        blockchain = self.__block_manager.get_blockchain()
        # util.logger.debug(f"-------------------_check_unconfirmed_block, "
        #                    f"candidate_blocks({len(self._block_manager.candidate_blocks.blocks)})")
        if blockchain.last_unconfirmed_block:
            vote = self.__block_manager.candidate_blocks.get_vote(
                blockchain.last_unconfirmed_block.header.hash)
            # util.logger.debug(f"-------------------_check_unconfirmed_block, "
            #                    f"last_unconfirmed_block({self._blockchain.last_unconfirmed_block.header.hash}), "
            #                    f"vote({vote.votes})")
            vote_result = vote.get_result(
                blockchain.last_unconfirmed_block.header.hash.hex(),
                conf.VOTING_RATIO)
            if not vote_result:
                util.logger.debug(
                    f"last_unconfirmed_block({blockchain.last_unconfirmed_block.header.hash}), "
                    f"vote result({vote_result})")

    def __add_tx_to_block(self, block_builder):
        tx_queue = self.__block_manager.get_tx_queue()

        block_tx_size = 0
        tx_versioner = self.__blockchain.tx_versioner
        while tx_queue:
            if block_tx_size >= conf.MAX_TX_SIZE_IN_BLOCK:
                logging.debug(
                    f"consensus_base total size({block_builder.size()}) "
                    f"count({len(block_builder.transactions)}) "
                    f"_txQueue size ({len(tx_queue)})")
                break

            tx: 'Transaction' = tx_queue.get_item_in_status(
                TransactionStatusInQueue.normal,
                TransactionStatusInQueue.added_to_block)
            if tx is None:
                break

            tv = TransactionVerifier.new(tx.version, tx_versioner)

            try:
                tv.verify(tx, self.__blockchain)
            except Exception as e:
                logging.warning(f"tx hash invalid.\n"
                                f"tx: {tx}\n"
                                f"exception: {e}")
                traceback.print_exc()
            else:
                block_builder.transactions[tx.hash] = tx
                block_tx_size += tx.size(tx_versioner)

    def makeup_block(self, complained: str):
        # self._check_unconfirmed_block(
        last_block = self.__blockchain.last_unconfirmed_block or self.__blockchain.last_block
        block_height = last_block.header.height + 1
        block_version = self.__blockchain.block_versioner.get_version(
            block_height)
        block_builder = BlockBuilder.new(block_version,
                                         self.__blockchain.tx_versioner)
        if not complained:
            self.__add_tx_to_block(block_builder)

        return block_builder