Пример #1
0
    def put_precommit_block(self, precommit_block: Block):
        # write precommit block to DB
        logging.debug(
            f"blockchain:put_precommit_block ({self.__channel_name}), hash ({precommit_block.block_hash})"
        )
        if self.__last_block.height < precommit_block.height:
            self.__precommit_tx(precommit_block)
            util.logger.spam(
                f"blockchain:put_precommit_block:confirmed_transaction_list")
            # for tx in precommit_block.confirmed_transaction_list:
            #     tx_hash = tx.tx_hash
            #     util.logger.spam(f"blockchain.py:put_precommit_block:{tx_hash}")

            results = self.__confirmed_block_db.Put(
                BlockChain.PRECOMMIT_BLOCK_KEY,
                precommit_block.serialize_block())

            util.logger.spam(f"result of to write to db ({results})")
            logging.info(
                f"ADD BLOCK PRECOMMIT HEIGHT : {precommit_block.height} , "
                f"HASH : {precommit_block.block_hash}, CHANNEL : {self.__channel_name}"
            )
        else:
            results = None
            logging.debug(
                f"blockchain:put_precommit_block::this precommit block is not validate. "
                f"the height of precommit block must be bigger than the last block."
                f"(last block:{self.__last_block.height}/precommit block:{precommit_block.height})"
            )

        return results
Пример #2
0
    def add_block(self, block: Block):
        """인증된 블럭만 추가합니다.

        :param block: 인증완료된 추가하고자 하는 블럭
        :return:
        """
        # util.logger.spam(f"blockchain:add_block --start--")
        if block.block_status is not BlockStatus.confirmed:
            raise BlockInValidError("미인증 블럭")
        elif self.__last_block is not None and self.__last_block.height > 0:
            if self.__last_block.block_hash != block.prev_block_hash:
                # 마지막 블럭의 hash값이 추가되는 블럭의 prev_hash값과 다르면 추가 하지 않고 익셉션을 냅니다.
                logging.debug("self.last_block.block_hash: " +
                              self.__last_block.block_hash)
                logging.debug("block.prev_block_hash: " +
                              block.prev_block_hash)
                raise BlockError("최종 블럭과 해쉬값이 다릅니다.")

        # util.logger.spam(f"blockchain:add_block --1-- {block.prev_block_hash}, {block.height}")
        if block.height == 0 or ObjectManager().peer_service is None:
            # all results to success
            success_result = {'code': int(message_code.Response.success)}
            invoke_results = self.__create_invoke_result_specific_case(
                block.confirmed_transaction_list, success_result)
        else:
            try:
                invoke_results = ObjectManager().peer_service.score_invoke(
                    block, self.__channel_name)

            except Exception as e:
                # When Grpc Connection Raise Exception
                # save all result{'code': ScoreResponse.SCORE_CONTAINER_EXCEPTION, 'message': str(e)}
                logging.error(f'Error While Invoke Score fail add block : {e}')
                score_container_exception_result = {
                    'code': ScoreResponse.SCORE_CONTAINER_EXCEPTION,
                    'message': str(e)
                }
                invoke_results = self.__create_invoke_result_specific_case(
                    block.confirmed_transaction_list,
                    score_container_exception_result)

        # util.logger.spam(f"blockchain:add_block --2--")
        self.__add_tx_to_block_db(block, invoke_results)

        block_hash_encoded = block.block_hash.encode(encoding='UTF-8')

        batch = leveldb.WriteBatch()
        batch.Put(block_hash_encoded, block.serialize_block())
        batch.Put(BlockChain.LAST_BLOCK_KEY, block_hash_encoded)
        batch.Put(
            BlockChain.BLOCK_HEIGHT_KEY + block.height.to_bytes(
                conf.BLOCK_HEIGHT_BYTES_LEN, byteorder='big'),
            block_hash_encoded)
        self.__confirmed_block_db.Write(batch)

        self.__last_block = block
        self.__block_height = self.__last_block.height

        # logging.debug("ADD BLOCK Height : %i", block.height)
        # logging.debug("ADD BLOCK Hash : %s", block.block_hash)
        # logging.debug("ADD BLOCK MERKLE TREE Hash : %s", block.merkle_tree_root_hash)
        # logging.debug("ADD BLOCK Prev Hash : %s ", block.prev_block_hash)
        logging.info("ADD BLOCK HEIGHT : %i , HASH : %s", block.height,
                     block.block_hash)
        # 블럭의 Transaction 의 데이터를 저장 합니다.
        # Peer에서 Score를 파라미터로 넘김으로써 체인코드를 실행합니다.

        # util.logger.spam(f"blockchain:add_block --end--")

        util.apm_event(
            self.__peer_id, {
                'event_type': 'AddBlock',
                'peer_id': self.__peer_id,
                'data': {
                    'block_height': self.__block_height,
                    'block_type': block.block_type.name
                }
            })

        return True
Пример #3
0
    def add_block(self, block: Block, is_commit_state_validation=False) -> bool:
        """add committed block

        :param block: a block after confirmation
        'STORE_VALID_TRANSACTION_ONLY'가 True로 설정 된 경우, 필수 parameter.
        :param is_commit_state_validation: if True: add only commit state validate pass
        :return: to add block is success or not
        """

        with self.__add_block_lock:
            util.logger.spam(f"ENGINE-308 blockchain:add_block is_commit_state_validation({is_commit_state_validation})")

            if block.height != 0 and block.height != (self.last_block.height + 1) and not is_commit_state_validation:
                logging.warning(f"blockchain:add_block invalid block height({block.height})")
                return False

            try:
                self.__verify_block_connection(block)
            except Exception as e:
                logging.error(f"add_block error! caused by : {e}")
                return False

            if conf.CHANNEL_OPTION[self.__channel_name]["send_tx_type"] == conf.SendTxType.icx and block.height == 0:
                invoke_results = ObjectManager().channel_service.genesis_invoke(block)
                ObjectManager().channel_service.score_write_precommit_state(block)
                self.__add_tx_to_block_db(block, invoke_results)
            elif not conf.CHANNEL_OPTION[self.__channel_name]['store_valid_transaction_only']:
                # STORE_VALID_TRANSACTION_ONLY
                if block.height == 0 or ObjectManager().channel_service is None:
                    # all results to success
                    success_result = {'code': int(message_code.Response.success)}
                    invoke_results = util.create_invoke_result_specific_case(
                        block.confirmed_transaction_list, success_result)
                    self.__add_tx_to_block_db(block, invoke_results)
                else:
                    try:
                        invoke_results = self.__score_invoke_with_state_integrity(block, is_commit_state_validation)
                    except Exception as e:
                        # When Grpc Connection Raise Exception
                        # save all result{'code': ScoreResponse.SCORE_CONTAINER_EXCEPTION, 'message': str(e)}
                        logging.error(f'Error While Invoke Score fail add block : {e}')
                        score_container_exception_result = {
                            'code': ScoreResponse.SCORE_CONTAINER_EXCEPTION, 'message': str(e)}
                        invoke_results = \
                            util.create_invoke_result_specific_case(
                                block.confirmed_transaction_list,
                                score_container_exception_result
                            )
                    self.__add_tx_to_block_db(block, invoke_results)
                    ObjectManager().channel_service.score_write_precommit_state(block)
            else:
                need_to_commit = True
                invoke_results = self.__invoke_results.get(block.block_hash, None)
                if not invoke_results:
                    need_to_commit = self.__prevent_next_block_mismatch(block, is_commit_state_validation)
                    if need_to_commit:
                        invoke_results = self.__score_invoke_with_state_integrity(block, is_commit_state_validation)

                try:
                    if need_to_commit:
                        self.__add_tx_to_block_db(block, invoke_results)
                        ObjectManager().channel_service.score_write_precommit_state(block)
                        # invoke_results = self.__invoke_results[block.block_hash]
                except Exception as e:
                    logging.warning(f"blockchain:add_block FAIL "
                                    f"channel_service.score_write_precommit_state")
                    raise e
                finally:
                    self.__invoke_results.pop(block.block_hash, None)

            # a condition for the exception case of genesis block.
            next_total_tx = self.__total_tx
            if block.height > 0:
                next_total_tx += block.confirmed_tx_len

            bit_length = next_total_tx.bit_length()
            byte_length = (bit_length + 7) // 8
            next_total_tx_bytes = next_total_tx.to_bytes(byte_length, byteorder='big')

            block_hash_encoded = block.block_hash.encode(encoding='UTF-8')

            batch = leveldb.WriteBatch()
            batch.Put(block_hash_encoded, block.serialize_block())
            batch.Put(BlockChain.LAST_BLOCK_KEY, block_hash_encoded)
            batch.Put(BlockChain.TRANSACTION_COUNT_KEY, next_total_tx_bytes)
            batch.Put(
                BlockChain.BLOCK_HEIGHT_KEY +
                block.height.to_bytes(conf.BLOCK_HEIGHT_BYTES_LEN, byteorder='big'),
                block_hash_encoded)
            self.__confirmed_block_db.Write(batch)

            self.__last_block = block
            self.__block_height = self.__last_block.height
            self.__total_tx = next_total_tx
            logging.debug(f"blockchain add_block set block_height({self.__block_height}), "
                          f"last_block({self.__last_block.block_hash})")
            logging.info(
                f"ADD BLOCK HEIGHT : {block.height} , HASH : {block.block_hash} , CHANNEL : {self.__channel_name}")

            util.apm_event(self.__peer_id, {
                'event_type': 'AddBlock',
                'peer_id': self.__peer_id,
                'peer_name': conf.PEER_NAME,
                'channel_name': self.__channel_name,
                'data': {
                    'block_height': self.__block_height,
                    'block_type': block.block_type.name}})

            return True