async def publish_new_block(ws, channel_name, height, peer_id): call_method = WSDispatcher.PUBLISH_NEW_BLOCK channel_stub = get_channel_stub_by_channel_name(channel_name) try: while True: new_block_dumped, confirm_info_bytes = await channel_stub.async_task().announce_new_block( subscriber_block_height=height, subscriber_id=peer_id ) new_block: dict = json.loads(new_block_dumped) if "error" in new_block: Logger.error(f"announce_new_block error: {new_block}, to citizen({peer_id})") break confirm_info = confirm_info_bytes.decode('utf-8') request = Request(call_method, block=new_block, confirm_info=confirm_info) Logger.debug(f"{call_method}: {request}") await ws.send(json.dumps(request)) height += 1 except exceptions.ConnectionClosed: Logger.debug("Connection Closed by child.") # TODO: Useful message needed. except Exception as e: traceback.print_exc() # TODO: Keep this tb? await WSDispatcher.send_exception( ws, call_method, exception=e, error_code=message_code.Response.fail_announce_block )
def _get_failure_from_exception( e: BaseException) -> TransactionResult.Failure: """ Gets `Failure` from an exception :param e: exception :return: a Failure """ if isinstance(e, IconServiceBaseException): if e.code == ExceptionCode.SCORE_ERROR or isinstance( e, ScoreErrorException): Logger.warning(e.message, ICON_SERVICE_LOG_TAG) else: Logger.exception(e.message, ICON_SERVICE_LOG_TAG) code = e.code message = e.message else: Logger.exception(e, ICON_SERVICE_LOG_TAG) Logger.error(e, ICON_SERVICE_LOG_TAG) code = ExceptionCode.SERVER_ERROR message = str(e) return TransactionResult.Failure(code, message)
def _get_failure_from_exception( e: BaseException) -> TransactionResult.Failure: """ Gets `Failure` from an exception :param e: exception :return: a Failure """ try: if isinstance(e, IconServiceBaseException): if e.code >= ExceptionCode.SCORE_ERROR or isinstance( e, IconScoreException): Logger.warning(e.message, ICON_SERVICE_LOG_TAG) else: Logger.exception(e.message, ICON_SERVICE_LOG_TAG) code = int(e.code) message = str(e.message) else: Logger.exception(e, ICON_SERVICE_LOG_TAG) Logger.error(e, ICON_SERVICE_LOG_TAG) code: int = ExceptionCode.SYSTEM_ERROR.value message = str(e) except: code: int = ExceptionCode.SYSTEM_ERROR.value message = 'Invalid exception: code or message is invalid' return TransactionResult.Failure(code, message)
def __init__(self): self.__app = Sanic(__name__, log_config=self._make_log_config()) self.__app.config.KEEP_ALIVE = False CORS(self.__app) # Decide whether to create context or not according to whether SSL is applied rest_ssl_type = ServerComponents.conf[ConfigKey.REST_SSL_TYPE] if rest_ssl_type == SSLAuthType.none: self.__ssl_context = None elif rest_ssl_type == SSLAuthType.server_only: self.__ssl_context = ( ServerComponents.conf[ConfigKey.DEFAULT_SSL_CERT_PATH], ServerComponents.conf[ConfigKey.DEFAULT_SSL_KEY_PATH]) elif rest_ssl_type == SSLAuthType.mutual: self.__ssl_context = ssl.SSLContext(_ssl.PROTOCOL_SSLv23) self.__ssl_context.verify_mode = _ssl.CERT_REQUIRED self.__ssl_context.check_hostname = False self.__ssl_context.load_verify_locations( cafile=ServerComponents.conf[ ConfigKey.DEFAULT_SSL_TRUST_CERT_PATH]) self.__ssl_context.load_cert_chain( ServerComponents.conf[ConfigKey.DEFAULT_SSL_CERT_PATH], ServerComponents.conf[ConfigKey.DEFAULT_SSL_KEY_PATH]) else: Logger.error( f"REST_SSL_TYPE must be one of [0,1,2]. But now conf.REST_SSL_TYPE is {rest_ssl_type}" )
def _check_claim_tx(context: 'IconScoreContext') -> bool: if context.tx.hash in INVALID_CLAIM_TX: Logger.error(tag=_TAG, msg=f"skip claim tx: {context.tx.hash.hex()}") return False else: return True
def clear_context_stack(self): """Clear IconScoreContext stacks """ stack_size: int = self._get_context_stack_size() assert stack_size == 0 if stack_size > 0: Logger.error(f'IconScoreContext leak is detected: {stack_size}', ICON_SERVICE_LOG_TAG) self._clear_context()
async def _check_rabbitmq(amqp_target: str): connection = None try: amqp_user_name = os.getenv("AMQP_USERNAME", "guest") amqp_password = os.getenv("AMQP_PASSWORD", "guest") connection = await aio_pika.connect(host=amqp_target, login=amqp_user_name, password=amqp_password) except ConnectionRefusedError: Logger.error("rabbitmq-service disable", _TAG) exit(0) finally: if connection: await connection.close()
async def _serve(): try: await self.init() except RuntimeError as e: msg = f'Failed to connect to MQ. Check rabbitMQ service. ({e})' Logger.error(msg, TBEARS_BLOCK_MANAGER) print(msg) self.close() # TODO how to notify process status to parent process or system return Logger.info(f'tbears block_manager service started!', TBEARS_BLOCK_MANAGER)
async def _check_rabbitmq(): connection = None try: amqp_user_name = os.getenv("AMQP_USERNAME", "guest") amqp_password = os.getenv("AMQP_PASSWORD", "guest") connection = await aio_pika.connect(login=amqp_user_name, password=amqp_password) connection.connect() except ConnectionRefusedError: Logger.error("rabbitmq-service disable", ICON_SERVICE_STANDALONE) exit(0) finally: if connection: await connection.close()
async def _run(conf: 'IconConfig'): redirect_protocol_env = os.getenv( camel_to_upper_snake(ConfigKey.REDIRECT_PROTOCOL)) if redirect_protocol_env: conf.update_conf({ConfigKey.REDIRECT_PROTOCOL: redirect_protocol_env}) Logger.print_config(conf, ICON_RPCSERVER_CLI) # Setup port and host values. host = '0.0.0.0' # Connect gRPC stub. PeerServiceStub().conf = conf PeerServiceStub().rest_grpc_timeout = \ conf[ConfigKey.GRPC_TIMEOUT] + conf[ConfigKey.REST_ADDITIONAL_TIMEOUT] PeerServiceStub().rest_score_query_timeout = \ conf[ConfigKey.SCORE_QUERY_TIMEOUT] + conf[ConfigKey.REST_ADDITIONAL_TIMEOUT] PeerServiceStub().set_stub_port( int(conf[ConfigKey.PORT]) - int(conf[ConfigKey.PORT_DIFF_REST_SERVICE_CONTAINER]), conf[ConfigKey.IP_LOCAL]) ServerComponents.conf = conf ServerComponents().set_resource() Logger.debug( f"Run gunicorn webserver for HA. Port = {conf[ConfigKey.PORT]}") # Configure SSL. ssl_context = ServerComponents().ssl_context certfile = "" keyfile = "" if ssl_context is not None: certfile = ssl_context[0] keyfile = ssl_context[1] options = { 'bind': f"{host}:{conf[ConfigKey.PORT]}", 'workers': conf[ConfigKey.GUNICORN_WORKER_COUNT], 'worker_class': "sanic.worker.GunicornWorker", 'certfile': certfile, 'SERVER_SOFTWARE': gunicorn.SERVER_SOFTWARE, 'keyfile': keyfile, 'capture_output': False } # Launch gunicorn web server. ServerComponents.conf = conf ServerComponents().ready() StandaloneApplication(ServerComponents().app, options).run() Logger.error("Rest App Done!")
def check_config(conf: dict, default_conf: dict) -> bool: checker = ConfigSanityChecker(default_conf) ret: bool = checker.run(conf) if len(checker.invalid_keys) > 0: Logger.info(tag=_TAG, msg="===== INVALID CONFIGURATION KEYS =====") for item in checker.invalid_keys: Logger.info(tag=_TAG, msg=f"{item}") if len(checker.invalid_values) > 0: Logger.error(tag=_TAG, msg="===== INVALID CONFIGURATION VALUE TYPES ===== ") for item in checker.invalid_values: Logger.error(tag=_TAG, msg=f"{item}") return ret
def main(): parser = argparse.ArgumentParser() parser.add_argument("-sc", dest=ConfigKey.SCORE_ROOT_PATH, type=str, default=None, help="icon score root path example : .score") parser.add_argument("-st", dest=ConfigKey.STATE_DB_ROOT_PATH, type=str, default=None, help="icon score state db root path example : .statedb") parser.add_argument("-ch", dest=ConfigKey.CHANNEL, type=str, default=None, help="icon score channel") parser.add_argument("-ak", dest=ConfigKey.AMQP_KEY, type=str, default=None, help="icon score amqp_key : [amqp_key]") parser.add_argument("-at", dest=ConfigKey.AMQP_TARGET, type=str, default=None, help="icon score amqp_target : [127.0.0.1]") parser.add_argument("-c", dest=ConfigKey.CONFIG, type=str, default=None, help="icon score config") parser.add_argument("-tbears", dest=ConfigKey.TBEARS_MODE, action='store_true', help="tbears mode") parser.add_argument("-steptrace", dest=ConfigKey.STEP_TRACE_FLAG, action="store_true", help="enable step tracing") args = parser.parse_args() args_params = dict(vars(args)) del args_params['config'] setproctitle.setproctitle(ICON_SERVICE_PROCTITLE_FORMAT.format(**args_params)) conf_path = args.config if conf_path is not None: if not IconConfig.valid_conf_path(conf_path): print(f'invalid config file : {conf_path}') sys.exit(ExitCode.INVALID_COMMAND.value) if conf_path is None: conf_path = str() conf = IconConfig(conf_path, copy.deepcopy(default_icon_config)) conf.load() conf.update_conf(args_to_dict(args)) Logger.load_config(conf) if not check_config(conf, default_icon_config): Logger.error(tag=_TAG, msg=f"Invalid Config") sys.exit(ExitCode.INVALID_CONFIG.value) Logger.print_config(conf, _TAG) _run_async(_check_rabbitmq(conf[ConfigKey.AMQP_TARGET])) icon_service = IconService() icon_service.serve(config=conf) Logger.info(f'==========IconService Done==========', _TAG)
def _is_removable_v0(cls, stake_part: 'StakePart', target: Target) -> bool: """Inspect stake_part.unstake and stake_part.unstake_block_height :param target: :param stake_part: :return: """ if len(target.unstakes) != 1: return False if len(stake_part.unstakes_info) != 0: Logger.error( tag=TAG, msg= f"Invalid stake_part.unstakes_info: {stake_part.unstakes_info}" ) return False unstake: 'Unstake' = target.unstakes[0] return (unstake.amount == stake_part.unstake and unstake.block_height == stake_part.unstake_block_height)
def _callback_connection_lost_callback(self, connection: 'RobustConnection'): Logger.error("MQ Connection lost.") self._task._close()
def _callback_connection_lost_callback(self, connection: 'RobustConnection'): Logger.error(f'ChannelService lost message queue connection', 'tbears_block_manager') self._task._block_manager.close()
def raise_exception_end_tag(tag: str = ""): emblem_str = '=' * 20 Logger.error(f'{emblem_str} [{tag}] raise exception end {emblem_str}')
async def _confirm_block(self, tx_list: list, invoke_response: dict, block_hash: str, timestamp: int): """ Confirm block. Send 'write_precommit_state' message and save transaction, transaction result and block data :param tx_list: transaction list :param invoke_response: invoke response :param block_hash: old block hash :param timestamp: block timestamp :return: """ Logger.debug(f'confirm block start. tx_list:{tx_list}, invoke_response:{invoke_response}', TBEARS_BLOCK_MANAGER) # Set new P-Rep list self._prep_manager.register_preps(invoke_response.get('prep')) # remake tx_list with addedTransactions in invoke_response added_transactions: dict = invoke_response.get('addedTransactions') if added_transactions is not None: for tx_hash, tx in added_transactions.items(): tx['txHash'] = tx_hash index: int = -1 # find txResult and index for i, tx_result in enumerate(invoke_response.get('txResults')): if tx_result.get('txHash') == tx_hash: index = i break # insert addedTransaction to tx_list if index != -1: tx_list.insert(index, tx) else: Logger.error(f"Can't find txResult of addedTransaction({tx_hash}: {tx})") # recalculate block_hash. tbears block_manager is dev util block_timestamp_us = int(time.time() * 10 ** 6) new_block_hash = create_hash(block_timestamp_us.to_bytes(DEFAULT_BYTE_SIZE, DATA_BYTE_ORDER)) block_height = self.block.block_height + 1 # save transaction result if block_height == 0: self.block.save_txresults_legacy(tx_list=tx_list, results=invoke_response) else: self.block.save_txresults(tx_results=invoke_response.get('txResults'), new_block_hash=new_block_hash) # save transactions self.block.save_transactions(tx_list=tx_list, block_hash=new_block_hash) # save block block_data = self._make_block_data(new_block_hash, tx_list, timestamp, invoke_response) self.block.save_block(block_data) self._prep_manager.prev_preps = self._prep_manager.prep_list # update block information self.block.commit_block(prev_block_hash=new_block_hash) precommit_request = {'blockHeight': hex(block_height), 'oldBlockHash': block_hash, 'newBlockHash': new_block_hash} # send write_precommit_state message to iconservice await self._icon_stub.async_task().write_precommit_state(precommit_request) Logger.debug(f'confirm block done.', TBEARS_BLOCK_MANAGER)
def test_error(self): Logger.error(TAG, 'error log')
def _callback_connection_reconnect_callback( self, connection: 'RobustConnection'): Logger.error("MQ Connection reconnect. [Service]")
def _callback_connection_lost_callback(self, connection: 'RobustConnection'): Logger.error("MQ Connection lost. [Stub]")
def _callback_connection_close(self, connection: 'RobustConnection'): Logger.error(f'[IconStub] close message queue connection', 'tbears_block_manager') self._task._block_manager.close()
def _log_exception(self, e: BaseException, tag: str = ICON_INNER_LOG_TAG) -> None: Logger.exception(e, tag) Logger.error(e, tag)
def test_error(self): Logger.error('error log') Logger.error('error log', TAG)
def serve(self, config: 'IconConfig'): async def _serve(): await self._inner_service.connect(exclusive=True) Logger.info(f'Start IconService Service serve!', ICON_SERVICE) channel = config[ConfigKey.CHANNEL] amqp_key = config[ConfigKey.AMQP_KEY] amqp_target = config[ConfigKey.AMQP_TARGET] score_root_path = config[ConfigKey.SCORE_ROOT_PATH] db_root_path = config[ConfigKey.STATE_DB_ROOT_PATH] self._set_icon_score_stub_params(channel, amqp_key, amqp_target) Logger.info(f'==========IconService Service params==========', ICON_SERVICE) Logger.info(f'score_root_path : {score_root_path}', ICON_SERVICE) Logger.info(f'icon_score_state_db_root_path : {db_root_path}', ICON_SERVICE) Logger.info(f'amqp_target : {amqp_target}', ICON_SERVICE) Logger.info(f'amqp_key : {amqp_key}', ICON_SERVICE) Logger.info(f'icon_score_queue_name : {self._icon_score_queue_name}', ICON_SERVICE) Logger.info(f'==========IconService Service params==========', ICON_SERVICE) # Before creating IconScoreInnerService instance, # loop SHOULD be set as a current event loop for the current thread. # Otherwise connection between iconservice and rc will be failed. loop = MessageQueueService.loop asyncio.set_event_loop(loop) try: self._inner_service = IconScoreInnerService( amqp_target, self._icon_score_queue_name, conf=config) except FatalException as e: Logger.exception(e, ICON_EXCEPTION_LOG_TAG) Logger.error(e, ICON_EXCEPTION_LOG_TAG) self._inner_service.clean_close() finally: Logger.debug( "icon service will be closed while open the icon service engine. " "check if the config is valid") loop.create_task(_serve()) loop.add_signal_handler(signal.SIGINT, self.close) loop.add_signal_handler(signal.SIGTERM, self.close) try: loop.run_forever() except FatalException as e: Logger.exception(e, ICON_EXCEPTION_LOG_TAG) Logger.error(e, ICON_EXCEPTION_LOG_TAG) self._inner_service.clean_close() finally: """ If the function is called when the operation is not an endless loop in an asynchronous function, the await is terminated immediately. """ Logger.debug("loop has been stopped and will be closed") loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
def _callback_connection_close(self, sender, exc: Optional[BaseException], *args, **kwargs): Logger.error(tag=_TAG, msg=f"[Inner Stub] connection closed. {exc}")
def _log_exception(e: BaseException, tag: str) -> None: Logger.exception(str(e), tag) Logger.error(str(e), tag)
def _callback_connection_close(self, exc: Exception): Logger.error( f'[ChannelTxCreatorService] close message queue connection. {exc}', 'tbears_block_manager') self._task._block_manager.close()