class IconScoreInnerTask(object): def __init__(self, conf: dict): self._conf = conf self._thread_flag = ENABLE_THREAD_FLAG self._icon_service_engine = IconServiceEngine() self._open() self._thread_pool = { THREAD_INVOKE: ThreadPoolExecutor(1), THREAD_STATUS: ThreadPoolExecutor(1), THREAD_QUERY: ThreadPoolExecutor(1), THREAD_ESTIMATE: ThreadPoolExecutor(1), THREAD_VALIDATE: ThreadPoolExecutor(1) } def _open(self): Logger.info(tag=_TAG, msg="_open() start") self._icon_service_engine.open(self._conf) Logger.info(tag=_TAG, msg="_open() end") def _is_thread_flag_on(self, flag: 'EnableThreadFlag') -> bool: return (self._thread_flag & flag) == flag def _check_icon_service_ready(self): if not self._icon_service_engine.is_reward_calculator_ready(): raise ServiceNotReadyException("Reward Calculator is not ready") @staticmethod def _log_exception(e: BaseException, tag: str) -> None: Logger.exception(str(e), tag) Logger.error(str(e), tag) @message_queue_task async def hello(self): Logger.info(tag=_TAG, msg='hello() start') ready_future = self._icon_service_engine.get_ready_future() await ready_future if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() ret = await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._hello) else: ret = self._hello() Logger.info(tag=_TAG, msg='hello() end') return ret def _hello(self): return self._icon_service_engine.hello() def cleanup(self): Logger.info(tag=_TAG, msg="cleanup() start") # shutdown thread pool executors for executor in self._thread_pool.values(): executor.shutdown() # close ICON Service if self._icon_service_engine: self._icon_service_engine.close() self._icon_service_engine = None Logger.info(tag=_TAG, msg="cleanup() end") @message_queue_task async def close(self): Logger.info(tag=_TAG, msg="close() stop event loop") self._close() @staticmethod def _close(): asyncio.get_event_loop().stop() @message_queue_task async def invoke(self, request: dict) -> dict: Logger.debug(tag=_TAG, msg=f'invoke() start') try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() ret: dict = await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._invoke, request) else: ret: dict = self._invoke(request) Logger.debug(tag=_TAG, msg=f'invoke() end') return ret def _invoke(self, request: dict): """Process transactions in a block :param request: :return: """ Logger.info(tag=_TAG, msg=f'INVOKE Request: {request}') try: params = TypeConverter.convert(request, ParamType.INVOKE) converted_block_params = params['block'] block = Block.from_dict(converted_block_params) Logger.info(tag=_TAG, msg=f'INVOKE: BH={block.height}') converted_tx_requests = params['transactions'] convert_tx_result_to_dict: bool = 'isBlockEditable' in params converted_is_block_editable = params.get('isBlockEditable', False) converted_prev_block_generator = params.get('prevBlockGenerator') converted_prev_block_validators = params.get('prevBlockValidators') converted_prev_votes = params.get('prevBlockVotes') tx_results, state_root_hash, added_transactions, next_preps, is_shutdown = \ self._icon_service_engine.invoke( block=block, tx_requests=converted_tx_requests, prev_block_generator=converted_prev_block_generator, prev_block_validators=converted_prev_block_validators, prev_block_votes=converted_prev_votes, is_block_editable=converted_is_block_editable ) if convert_tx_result_to_dict: convert_tx_results = [tx_result.to_dict(to_camel_case) for tx_result in tx_results] else: # old version convert_tx_results = {bytes.hex(tx_result.tx_hash): tx_result.to_dict(to_camel_case) for tx_result in tx_results} results = { 'txResults': convert_tx_results, 'stateRootHash': bytes.hex(state_root_hash), 'addedTransactions': added_transactions } if next_preps: results["prep"] = next_preps if is_shutdown: results["is_shutdown"] = True response = MakeResponse.make_response(results) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except InvalidBaseTransactionException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) finally: if self._icon_service_engine: self._icon_service_engine.clear_context_stack() Logger.info(tag=_TAG, msg=f'INVOKE Response: {json.dumps(response, cls=BytesToHexJSONEncoder)}') return response @message_queue_task async def query(self, request: dict) -> dict: try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) return await self._get_query_response(request) async def _get_query_response(self, request: dict) -> dict: try: value = await self._execute_query(request) if isinstance(value, Address): value = str(value) response = MakeResponse.make_response(value) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) self._icon_service_engine.clear_context_stack() return response async def _execute_query(self, request: dict): method_name: str = request['method'] if method_name == RPCMethod.DEBUG_ESTIMATE_STEP: method: callable = self._estimate args = [request] else: method: callable = self._query args = [request, method_name] if self._is_thread_flag_on(EnableThreadFlag.QUERY): return await asyncio.get_event_loop(). \ run_in_executor(self._thread_pool[QUERY_THREAD_MAPPER[method_name]], method, *args) else: return method(*args) def _estimate(self, request: dict): converted_request = TypeConverter.convert(request, ParamType.INVOKE_TRANSACTION) return self._icon_service_engine.estimate_step(converted_request) def _query(self, request: dict, method: str): converted_request = TypeConverter.convert(request, ParamType.QUERY) return self._icon_service_engine.query(method, converted_request['params']) @message_queue_task async def call(self, request: dict): Logger.info(tag=_TAG, msg=f'call() start: {request}') try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) if self._is_thread_flag_on(EnableThreadFlag.QUERY): loop = asyncio.get_event_loop() ret = await loop.run_in_executor(self._thread_pool[THREAD_QUERY], self._call, request) else: ret = self._call(request) Logger.info(tag=_TAG, msg=f'call() end: {ret}') return ret def _call(self, request: dict): try: response = self._icon_service_engine.inner_call(request) if isinstance(response, Address): response = str(response) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) return response @message_queue_task async def write_precommit_state(self, request: dict): try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() ret = await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._write_precommit_state, request) else: ret = self._write_precommit_state(request) return ret def _write_precommit_state(self, request: dict) -> dict: Logger.info(tag=_TAG, msg=f'WRITE_PRECOMMIT_STATE Request: {request}') try: converted_params = TypeConverter.convert(request, ParamType.WRITE_PRECOMMIT) block_height: int = converted_params[ConstantKeys.BLOCK_HEIGHT] instant_block_hash: bytes = converted_params[ConstantKeys.OLD_BLOCK_HASH] block_hash = converted_params[ConstantKeys.NEW_BLOCK_HASH] Logger.info(tag=_TAG, msg=f'WRITE_PRECOMMIT_STATE: ' f'BH={block_height} ' f'instant_block_hash={bytes_to_hex(instant_block_hash)} ' f'block_hash={bytes_to_hex(block_hash)}') self._icon_service_engine.commit(block_height, instant_block_hash, block_hash) response = MakeResponse.make_response(ExceptionCode.OK) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) Logger.info(tag=_TAG, msg=f'WRITE_PRECOMMIT_STATE Response: {response}') return response @message_queue_task async def remove_precommit_state(self, request: dict): Logger.info(tag=_TAG, msg=f'remove_precommit_state() start') try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) """ Unused API """ return {} @message_queue_task async def rollback(self, request: dict): """Go back to the state of the given previous block :param request: :return: """ Logger.info(tag=_TAG, msg=f"rollback() start") try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() response = await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._rollback, request) else: response = self._rollback(request) Logger.info(tag=_TAG, msg=f"rollback() end") return response def _rollback(self, request: dict) -> dict: Logger.info(tag=_TAG, msg=f"ROLLBACK Request: {request}") try: converted_params = TypeConverter.convert(request, ParamType.ROLLBACK) block_height: int = converted_params[ConstantKeys.BLOCK_HEIGHT] block_hash: bytes = converted_params[ConstantKeys.BLOCK_HASH] Logger.info(tag=_TAG, msg=f"ROLLBACK: BH={block_height} block_hash={bytes_to_hex(block_hash)}") response: dict = self._icon_service_engine.rollback(block_height, block_hash) response = MakeResponse.make_response(response) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except BaseException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) Logger.info(tag=_TAG, msg=f"ROLLBACK Response: {response}") return response @message_queue_task async def validate_transaction(self, request: dict): try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) if self._is_thread_flag_on(EnableThreadFlag.VALIDATE): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_VALIDATE], self._validate_transaction, request) else: return self._validate_transaction(request) def _validate_transaction(self, request: dict): try: Logger.info(tag=_TAG, msg=f'validate_transaction Request: {request}') converted_request = TypeConverter.convert(request, ParamType.VALIDATE_TRANSACTION) self._icon_service_engine.validate_transaction(converted_request, request) response = MakeResponse.make_response(ExceptionCode.OK) except FatalException as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, _TAG) response = MakeResponse.make_error_response(icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def change_block_hash(self, _params): try: self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) return ExceptionCode.OK @message_queue_task async def dos_guard(self, params: dict) -> dict: try: Logger.info(tag=_TAG, msg=f'dos_guard: params: {params}') self._check_icon_service_ready() except ServiceNotReadyException as e: return MakeResponse.make_error_response(e.code, str(e)) try: self._icon_service_engine.dos_guard.run(_from=params["from"]) response = MakeResponse.make_response(ExceptionCode.OK) except Exception as e: self._log_exception(e, _TAG) response = MakeResponse.make_error_response(ExceptionCode.SYSTEM_ERROR, str(e)) return response
class IconScoreInnerTask(object): def __init__(self, conf: 'IconConfig'): self._conf = conf self._thread_flag = ENABLE_THREAD_FLAG self._icon_service_engine = IconServiceEngine() self._open() self._thread_pool = { THREAD_INVOKE: ThreadPoolExecutor(1), THREAD_QUERY: ThreadPoolExecutor(1), THREAD_VALIDATE: ThreadPoolExecutor(1) } def _open(self): Logger.info("icon_score_service open", ICON_INNER_LOG_TAG) self._icon_service_engine.open(self._conf) def _is_thread_flag_on(self, flag: 'EnableThreadFlag') -> bool: return (self._thread_flag & flag) == flag def _check_icon_service_ready(self): if not self._icon_service_engine.is_reward_calculator_ready(): raise ServiceNotReadyException("Reward Calculator is not ready") @staticmethod def _log_exception(e: BaseException, tag: str = ICON_INNER_LOG_TAG) -> None: Logger.exception(str(e), tag) Logger.error(str(e), tag) @message_queue_task async def hello(self): Logger.info('hello() start', ICON_INNER_LOG_TAG) ready_future = self._icon_service_engine.get_ready_future() await ready_future if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() ret = await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._hello) else: ret = self._hello() Logger.info('hello() end', ICON_INNER_LOG_TAG) return ret def _hello(self): return self._icon_service_engine.hello() def _close(self): Logger.info(tag=_TAG, msg="_close() start") if self._icon_service_engine: self._icon_service_engine.close() self._icon_service_engine = None MessageQueueService.loop.stop() Logger.info(tag=_TAG, msg="_close() end") @message_queue_task async def close(self): Logger.info(tag=_TAG, msg="close() start") self._close() Logger.info(tag=_TAG, msg="close() end") @message_queue_task async def invoke(self, request: dict): Logger.info(f'invoke request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._invoke, request) else: return self._invoke(request) def _invoke(self, request: dict): """Process transactions in a block :param request: :return: """ response = None try: params = TypeConverter.convert(request, ParamType.INVOKE) converted_block_params = params['block'] block = Block.from_dict(converted_block_params) converted_tx_requests = params['transactions'] convert_tx_result_to_dict: bool = 'isBlockEditable' in params converted_is_block_editable = params.get('isBlockEditable', False) converted_prev_block_generator = params.get('prevBlockGenerator') converted_prev_block_validators = params.get('prevBlockValidators') converted_prev_votes = params.get('prevBlockVotes') tx_results, state_root_hash, added_transactions, main_prep_as_dict = self._icon_service_engine.invoke( block=block, tx_requests=converted_tx_requests, prev_block_generator=converted_prev_block_generator, prev_block_validators=converted_prev_block_validators, prev_block_votes=converted_prev_votes, is_block_editable=converted_is_block_editable) if convert_tx_result_to_dict: convert_tx_results = [ tx_result.to_dict(to_camel_case) for tx_result in tx_results ] else: # old version convert_tx_results = { bytes.hex(tx_result.tx_hash): tx_result.to_dict(to_camel_case) for tx_result in tx_results } results = { 'txResults': convert_tx_results, 'stateRootHash': bytes.hex(state_root_hash), 'addedTransactions': added_transactions } if main_prep_as_dict: results["prep"] = main_prep_as_dict Logger.info(f'invoke origin response with {results}', ICON_INNER_LOG_TAG) response = MakeResponse.make_response(results) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except InvalidBaseTransactionException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: if self._icon_service_engine: self._icon_service_engine.clear_context_stack() return response @message_queue_task async def query(self, request: dict): Logger.debug(f'query request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.QUERY): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_QUERY], self._query, request) else: return self._query(request) def _query(self, request: dict): response = None try: method = request['method'] if method == 'debug_estimateStep': converted_request = TypeConverter.convert( request, ParamType.INVOKE_TRANSACTION) value = self._icon_service_engine.estimate_step( converted_request) else: converted_request = TypeConverter.convert( request, ParamType.QUERY) value = self._icon_service_engine.query( method, converted_request['params']) if isinstance(value, Address): value = str(value) response = MakeResponse.make_response(value) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.debug(f'query response with {response}', ICON_INNER_LOG_TAG) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def call(self, request: dict): Logger.info(f'call request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.QUERY): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_QUERY], self._call, request) else: return self._call(request) def _call(self, request: dict): response = None try: response = self._icon_service_engine.inner_call(request) if isinstance(response, Address): response = str(response) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'call response with {response}', ICON_INNER_LOG_TAG) return response @message_queue_task async def write_precommit_state(self, request: dict): Logger.info(f'write_precommit_state request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._write_precommit_state, request) else: return self._write_precommit_state(request) @staticmethod def _get_block_info_for_precommit_state( converted_block_params: dict ) -> Tuple[int, bytes, Optional[bytes]]: block_height: int = converted_block_params[ConstantKeys.BLOCK_HEIGHT] block_hash: Optional[bytes] = None if ConstantKeys.BLOCK_HASH in converted_block_params: instant_block_hash: bytes = converted_block_params[ ConstantKeys.BLOCK_HASH] else: instant_block_hash: bytes = converted_block_params[ ConstantKeys.OLD_BLOCK_HASH] block_hash = converted_block_params[ConstantKeys.NEW_BLOCK_HASH] return block_height, instant_block_hash, block_hash def _write_precommit_state(self, request: dict): response = None try: converted_block_params = TypeConverter.convert( request, ParamType.WRITE_PRECOMMIT) block_height, instant_block_hash, block_hash = \ self._get_block_info_for_precommit_state(converted_block_params) self._icon_service_engine.commit(block_height, instant_block_hash, block_hash) response = MakeResponse.make_response(ExceptionCode.OK) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'write_precommit_state response with {response}', ICON_INNER_LOG_TAG) return response @message_queue_task async def remove_precommit_state(self, request: dict): Logger.info(f'remove_precommit_state request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._remove_precommit_state, request) else: return self._remove_precommit_state(request) def _remove_precommit_state(self, request: dict): response = None try: converted_block_params = TypeConverter.convert( request, ParamType.WRITE_PRECOMMIT) block_height, instant_block_hash, _ = \ self._get_block_info_for_precommit_state(converted_block_params) self._icon_service_engine.remove_precommit_state( block_height, instant_block_hash) response = MakeResponse.make_response(ExceptionCode.OK) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'remove_precommit_state response with {response}', ICON_INNER_LOG_TAG) return response @message_queue_task async def rollback(self, request: dict): """Go back to the state of the given previous block :param request: :return: """ Logger.info(tag=ICON_INNER_LOG_TAG, msg=f"rollback() start: {request}") self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = asyncio.get_event_loop() response = await loop.run_in_executor( self._thread_pool[THREAD_INVOKE], self._rollback, request) else: response = self._rollback(request) Logger.info(tag=ICON_INNER_LOG_TAG, msg=f"rollback() end: {response}") return response def _rollback(self, request: dict) -> dict: Logger.info(tag=ICON_INNER_LOG_TAG, msg=f"_rollback() start: {request}") response = {} try: converted_params = TypeConverter.convert(request, ParamType.ROLLBACK) block_height: int = converted_params[ConstantKeys.BLOCK_HEIGHT] block_hash: bytes = converted_params[ConstantKeys.BLOCK_HASH] response: dict = self._icon_service_engine.rollback( block_height, block_hash) response = MakeResponse.make_response(response) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) self._close() except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except BaseException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(tag=ICON_INNER_LOG_TAG, msg=f"_rollback() end: {response}") return response @message_queue_task async def validate_transaction(self, request: dict): Logger.debug(f'pre_validate_check request with {request}', ICON_INNER_LOG_TAG) self._check_icon_service_ready() if self._is_thread_flag_on(EnableThreadFlag.VALIDATE): loop = asyncio.get_event_loop() return await loop.run_in_executor( self._thread_pool[THREAD_VALIDATE], self._validate_transaction, request) else: return self._validate_transaction(request) def _validate_transaction(self, request: dict): response = None try: converted_request = TypeConverter.convert( request, ParamType.VALIDATE_TRANSACTION) self._icon_service_engine.validate_transaction(converted_request) response = MakeResponse.make_response(ExceptionCode.OK) except FatalException as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.debug(f'pre_validate_check response with {response}', ICON_INNER_LOG_TAG) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def change_block_hash(self, _params): self._check_icon_service_ready() return ExceptionCode.OK
class IconScoreInnerTask(object): def __init__(self, conf: 'IconConfig'): self._conf = conf self._thread_flag = ENABLE_THREAD_FLAG self._icon_service_engine = IconServiceEngine() self._open() self._thread_pool = { THREAD_INVOKE: ThreadPoolExecutor(1), THREAD_QUERY: ThreadPoolExecutor(1), THREAD_VALIDATE: ThreadPoolExecutor(1) } def _open(self): Logger.info("icon_score_service open", ICON_INNER_LOG_TAG) self._icon_service_engine.open(self._conf) def _is_thread_flag_on(self, flag: 'EnableThreadFlag') -> bool: return (self._thread_flag & flag) == flag def _log_exception(self, e: BaseException, tag: str = ICON_INNER_LOG_TAG) -> None: Logger.exception(e, tag) Logger.error(e, tag) @message_queue_task async def hello(self): Logger.info('icon_score_hello', ICON_INNER_LOG_TAG) def _close(self): Logger.info("icon_score_service close", ICON_INNER_LOG_TAG) if self._icon_service_engine: self._icon_service_engine.close() self._icon_service_engine = None MessageQueueService.loop.stop() @message_queue_task async def close(self): self._close() @message_queue_task async def invoke(self, request: dict): Logger.info(f'invoke request with {request}', ICON_INNER_LOG_TAG) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._invoke, request) else: return self._invoke(request) def _invoke(self, request: dict): """Process transactions in a block :param request: :return: """ response = None try: params = TypeConverter.convert(request, ParamType.INVOKE) converted_block_params = params['block'] block = Block.from_dict(converted_block_params) converted_tx_requests = params['transactions'] tx_results, state_root_hash = self._icon_service_engine.invoke( block=block, tx_requests=converted_tx_requests) convert_tx_results = \ {bytes.hex(tx_result.tx_hash): tx_result.to_dict(to_camel_case) for tx_result in tx_results} results = { 'txResults': convert_tx_results, 'stateRootHash': bytes.hex(state_root_hash) } response = MakeResponse.make_response(results) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'invoke response with {response}', ICON_INNER_LOG_TAG) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def query(self, request: dict): Logger.info(f'query request with {request}', ICON_INNER_LOG_TAG) if self._is_thread_flag_on(EnableThreadFlag.QUERY): loop = get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_QUERY], self._query, request) else: return self._query(request) def _query(self, request: dict): response = None try: method = request['method'] if method == 'debug_estimateStep': converted_request = TypeConverter.convert( request, ParamType.INVOKE_TRANSACTION) value = self._icon_service_engine.estimate_step( converted_request) else: converted_request = TypeConverter.convert( request, ParamType.QUERY) value = self._icon_service_engine.query( method, converted_request['params']) if isinstance(value, Address): value = str(value) response = MakeResponse.make_response(value) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'query response with {response}', ICON_INNER_LOG_TAG) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def write_precommit_state(self, request: dict): Logger.info(f'write_precommit_state request with {request}', ICON_INNER_LOG_TAG) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._write_precommit_state, request) else: return self._write_precommit_state(request) def _write_precommit_state(self, request: dict): response = None try: converted_block_params = TypeConverter.convert( request, ParamType.WRITE_PRECOMMIT) block = Block.from_dict(converted_block_params) self._icon_service_engine.commit(block) response = MakeResponse.make_response(ExceptionCode.OK) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'write_precommit_state response with {response}', ICON_INNER_LOG_TAG) return response @message_queue_task async def remove_precommit_state(self, request: dict): Logger.info(f'remove_precommit_state request with {request}', ICON_INNER_LOG_TAG) if self._is_thread_flag_on(EnableThreadFlag.INVOKE): loop = get_event_loop() return await loop.run_in_executor(self._thread_pool[THREAD_INVOKE], self._remove_precommit_state, request) else: return self._remove_precommit_state(request) def _remove_precommit_state(self, request: dict): response = None try: converted_block_params = TypeConverter.convert( request, ParamType.WRITE_PRECOMMIT) block = Block.from_dict(converted_block_params) self._icon_service_engine.rollback(block) response = MakeResponse.make_response(ExceptionCode.OK) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'remove_precommit_state response with {response}', ICON_INNER_LOG_TAG) return response @message_queue_task async def validate_transaction(self, request: dict): Logger.info(f'pre_validate_check request with {request}', ICON_INNER_LOG_TAG) if self._is_thread_flag_on(EnableThreadFlag.VALIDATE): loop = get_event_loop() return await loop.run_in_executor( self._thread_pool[THREAD_VALIDATE], self._validate_transaction, request) else: return self._validate_transaction(request) def _validate_transaction(self, request: dict): response = None try: converted_request = TypeConverter.convert( request, ParamType.VALIDATE_TRANSACTION) self._icon_service_engine.validate_transaction(converted_request) response = MakeResponse.make_response(ExceptionCode.OK) except IconServiceBaseException as icon_e: self._log_exception(icon_e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( icon_e.code, icon_e.message) except Exception as e: self._log_exception(e, ICON_SERVICE_LOG_TAG) response = MakeResponse.make_error_response( ExceptionCode.SYSTEM_ERROR, str(e)) finally: Logger.info(f'pre_validate_check response with {response}', ICON_INNER_LOG_TAG) self._icon_service_engine.clear_context_stack() return response @message_queue_task async def change_block_hash(self, params): return ExceptionCode.OK