Exemple #1
0
    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}"
            )
Exemple #5
0
 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()
Exemple #8
0
        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)
Exemple #9
0
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()
Exemple #10
0
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)
Exemple #14
0
 def _callback_connection_lost_callback(self, connection: 'RobustConnection'):
     Logger.error("MQ Connection lost.")
     self._task._close()
Exemple #15
0
 def _callback_connection_lost_callback(self,
                                        connection: 'RobustConnection'):
     Logger.error(f'ChannelService lost message queue connection',
                  'tbears_block_manager')
     self._task._block_manager.close()
Exemple #16
0
def raise_exception_end_tag(tag: str = ""):
    emblem_str = '=' * 20
    Logger.error(f'{emblem_str} [{tag}] raise exception end {emblem_str}')
Exemple #17
0
    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)
Exemple #18
0
 def test_error(self):
     Logger.error(TAG, 'error log')
Exemple #19
0
 def _callback_connection_reconnect_callback(
         self, connection: 'RobustConnection'):
     Logger.error("MQ Connection reconnect. [Service]")
Exemple #20
0
 def _callback_connection_lost_callback(self,
                                        connection: 'RobustConnection'):
     Logger.error("MQ Connection lost. [Stub]")
Exemple #21
0
 def _callback_connection_close(self, connection: 'RobustConnection'):
     Logger.error(f'[IconStub] close message queue connection',
                  'tbears_block_manager')
     self._task._block_manager.close()
Exemple #22
0
 def _log_exception(self,
                    e: BaseException,
                    tag: str = ICON_INNER_LOG_TAG) -> None:
     Logger.exception(e, tag)
     Logger.error(e, tag)
Exemple #23
0
 def test_error(self):
     Logger.error('error log')
     Logger.error('error log', TAG)
Exemple #24
0
    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()
Exemple #25
0
 def _callback_connection_close(self, sender, exc: Optional[BaseException], *args, **kwargs):
     Logger.error(tag=_TAG, msg=f"[Inner Stub] connection closed. {exc}")
Exemple #26
0
 def _log_exception(e: BaseException, tag: str) -> None:
     Logger.exception(str(e), tag)
     Logger.error(str(e), tag)
Exemple #27
0
 def _callback_connection_close(self, exc: Exception):
     Logger.error(
         f'[ChannelTxCreatorService] close message queue connection. {exc}',
         'tbears_block_manager')
     self._task._block_manager.close()