From cfa46edec578e95b6e9c338b2b8108d9e97bf438 Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Fri, 1 Nov 2024 14:40:55 -0700 Subject: [PATCH 1/5] Some daemon start cleanup --- chia/cmds/start_funcs.py | 15 ++++++-------- chia/daemon/client.py | 45 ++++++++++++++++++++++++++-------------- chia/daemon/server.py | 13 ------------ 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/chia/cmds/start_funcs.py b/chia/cmds/start_funcs.py index 6340abb0704e..618a7a796482 100644 --- a/chia/cmds/start_funcs.py +++ b/chia/cmds/start_funcs.py @@ -33,9 +33,11 @@ def launch_start_daemon(root_path: Path) -> subprocess.Popen: print(f"Starting daemon: {cmd_to_execute} run_daemon --wait-for-unlock", flush=True) process = subprocess.Popen( [cmd_to_execute, "run_daemon", "--wait-for-unlock"], - encoding="utf-8", - stdout=subprocess.PIPE, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + stdin=subprocess.DEVNULL, creationflags=creationflags, + start_new_session=True, ) return process @@ -48,13 +50,8 @@ async def create_start_daemon_connection( if connection is None: print("Starting daemon", flush=True) # launch a daemon - process = launch_start_daemon(root_path) - # give the daemon a chance to start up - if process.stdout: - process.stdout.readline() - await asyncio.sleep(1) - # it prints "daemon: listening" - connection = await connect_to_daemon_and_validate(root_path, config) + launch_start_daemon(root_path) + connection = await connect_to_daemon_and_validate(root_path, config, wait_for_start=True) if connection: if skip_keyring: print("Skipping to unlock keyring") diff --git a/chia/daemon/client.py b/chia/daemon/client.py index 3a4866ab2f95..3d107fdd0c52 100644 --- a/chia/daemon/client.py +++ b/chia/daemon/client.py @@ -36,20 +36,31 @@ def format_request(self, command: str, data: dict[str, Any]) -> WsRpcMessage: request = create_payload_dict(command, data, "client", "daemon") return request - async def start(self) -> None: - try: - self.client_session = aiohttp.ClientSession() - self.websocket = await self.client_session.ws_connect( - self._uri, - autoclose=True, - autoping=True, - heartbeat=self.heartbeat, - ssl=self.ssl_context if self.ssl_context is not None else True, - max_msg_size=self.max_message_size, - ) - except Exception: + async def start(self, wait_for_start: bool = False) -> None: + + self.client_session = aiohttp.ClientSession() + + connect_backoff = 2 + while (self.websocket is None or self.websocket.closed) and connect_backoff <= 60: + try: + self.websocket = await self.client_session.ws_connect( + self._uri, + autoclose=True, + autoping=True, + heartbeat=self.heartbeat, + ssl=self.ssl_context if self.ssl_context is not None else True, + max_msg_size=self.max_message_size, + ) + break + except aiohttp.ClientError: + if not wait_for_start: + break + await asyncio.sleep(connect_backoff) + connect_backoff = connect_backoff * 2 + + if self.websocket is None or self.websocket.closed: await self.close() - raise + raise Exception("Failed to connect to daemon") async def listener_task() -> None: try: @@ -161,7 +172,7 @@ async def get_keys_for_plotting(self, fingerprints: Optional[list[uint32]] = Non async def connect_to_daemon( - self_hostname: str, daemon_port: int, max_message_size: int, ssl_context: ssl.SSLContext, heartbeat: int + self_hostname: str, daemon_port: int, max_message_size: int, ssl_context: ssl.SSLContext, heartbeat: int, wait_for_start: bool = False ) -> DaemonProxy: """ Connect to the local daemon. @@ -173,12 +184,13 @@ async def connect_to_daemon( max_message_size=max_message_size, heartbeat=heartbeat, ) - await client.start() + + await client.start(wait_for_start=wait_for_start) return client async def connect_to_daemon_and_validate( - root_path: Path, config: dict[str, Any], quiet: bool = False + root_path: Path, config: dict[str, Any], quiet: bool = False, wait_for_start: bool = False ) -> Optional[DaemonProxy]: """ Connect to the local daemon and do a ping to ensure that something is really @@ -200,6 +212,7 @@ async def connect_to_daemon_and_validate( max_message_size=daemon_max_message_size, ssl_context=ssl_context, heartbeat=daemon_heartbeat, + wait_for_start=wait_for_start, ) r = await connection.ping() diff --git a/chia/daemon/server.py b/chia/daemon/server.py index ea9c64948273..1c534c1a0cd0 100644 --- a/chia/daemon/server.py +++ b/chia/daemon/server.py @@ -1547,18 +1547,6 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in key_path = root_path / config["daemon_ssl"]["private_key"] ca_crt_path = root_path / config["private_ssl_ca"]["crt"] ca_key_path = root_path / config["private_ssl_ca"]["key"] - sys.stdout.flush() - json_msg = dict_to_json_str( - { - "message": "cert_path", - "success": True, - "cert": f"{crt_path}", - "key": f"{key_path}", - "ca_crt": f"{ca_crt_path}", - } - ) - sys.stdout.write("\n" + json_msg + "\n") - sys.stdout.flush() try: with Lockfile.create(daemon_launch_lock_path(root_path), timeout=1): log.info(f"chia-blockchain version: {chia_short_version()}") @@ -1587,7 +1575,6 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in await beta_metrics.stop_logging() log.info("Daemon WebSocketServer closed") - sys.stdout.close() return 0 except LockfileError: print("daemon: already launching") From 89d624fc37c9b22113838add70d554b0b8ede57d Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Mon, 4 Nov 2024 15:06:45 -0800 Subject: [PATCH 2/5] mypy fixes --- chia/daemon/client.py | 8 ++++++-- chia/daemon/keychain_proxy.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/chia/daemon/client.py b/chia/daemon/client.py index 3d107fdd0c52..624f8315ed37 100644 --- a/chia/daemon/client.py +++ b/chia/daemon/client.py @@ -37,7 +37,6 @@ def format_request(self, command: str, data: dict[str, Any]) -> WsRpcMessage: return request async def start(self, wait_for_start: bool = False) -> None: - self.client_session = aiohttp.ClientSession() connect_backoff = 2 @@ -172,7 +171,12 @@ async def get_keys_for_plotting(self, fingerprints: Optional[list[uint32]] = Non async def connect_to_daemon( - self_hostname: str, daemon_port: int, max_message_size: int, ssl_context: ssl.SSLContext, heartbeat: int, wait_for_start: bool = False + self_hostname: str, + daemon_port: int, + max_message_size: int, + ssl_context: ssl.SSLContext, + heartbeat: int, + wait_for_start: bool = False, ) -> DaemonProxy: """ Connect to the local daemon. diff --git a/chia/daemon/keychain_proxy.py b/chia/daemon/keychain_proxy.py index 2bbdbc89ded1..b7330c2cc8f5 100644 --- a/chia/daemon/keychain_proxy.py +++ b/chia/daemon/keychain_proxy.py @@ -98,7 +98,7 @@ async def _get(self, request: WsRpcMessage) -> WsRpcMessage: except asyncio.TimeoutError: raise KeychainProxyConnectionTimeout() - async def start(self) -> None: + async def start(self, wait_for_start: bool = False) -> None: self.keychain_connection_task = asyncio.create_task(self.connect_to_keychain()) await self.connection_established.wait() # wait until connection is established. From 0669ba79df7cab4d88aa835bc4a7015f148b8114 Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Mon, 4 Nov 2024 15:08:18 -0800 Subject: [PATCH 3/5] Reduce scopy of change --- chia/daemon/server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chia/daemon/server.py b/chia/daemon/server.py index a47f431e54d7..c1a2a63a7698 100644 --- a/chia/daemon/server.py +++ b/chia/daemon/server.py @@ -1547,6 +1547,7 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in key_path = root_path / config["daemon_ssl"]["private_key"] ca_crt_path = root_path / config["private_ssl_ca"]["crt"] ca_key_path = root_path / config["private_ssl_ca"]["key"] + sys.stdout.flush() try: with Lockfile.create(daemon_launch_lock_path(root_path), timeout=1): log.info(f"chia-blockchain version: {chia_short_version()}") @@ -1575,6 +1576,7 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in await beta_metrics.stop_logging() log.info("Daemon WebSocketServer closed") + sys.stderr.close() return 0 except LockfileError: print("daemon: already launching") From d551efcfe493cb6f4a6359e8cc27b335079812dd Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Mon, 4 Nov 2024 15:08:46 -0800 Subject: [PATCH 4/5] typo --- chia/daemon/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chia/daemon/server.py b/chia/daemon/server.py index c1a2a63a7698..b239be64efbe 100644 --- a/chia/daemon/server.py +++ b/chia/daemon/server.py @@ -1576,7 +1576,7 @@ async def async_run_daemon(root_path: Path, wait_for_unlock: bool = False) -> in await beta_metrics.stop_logging() log.info("Daemon WebSocketServer closed") - sys.stderr.close() + sys.stdout.close() return 0 except LockfileError: print("daemon: already launching") From 47016353b9d85328e9090e588ad76fa4981dbc35 Mon Sep 17 00:00:00 2001 From: Earle Lowe Date: Tue, 12 Nov 2024 12:29:01 -0800 Subject: [PATCH 5/5] Use *= --- chia/daemon/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chia/daemon/client.py b/chia/daemon/client.py index 624f8315ed37..9ae1a8e8d9cd 100644 --- a/chia/daemon/client.py +++ b/chia/daemon/client.py @@ -55,7 +55,7 @@ async def start(self, wait_for_start: bool = False) -> None: if not wait_for_start: break await asyncio.sleep(connect_backoff) - connect_backoff = connect_backoff * 2 + connect_backoff *= 2 if self.websocket is None or self.websocket.closed: await self.close()