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
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
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