From 2e72a8ce1bae4670b82932794505c0a485a1c0f4 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 21 Feb 2025 12:21:09 +0100 Subject: [PATCH] fix(python/debuglink): time out after waiting for empty-state response ...avoiding a problem where, if the timing is unfortunate, the reply may get lost when a workflow is ending (cherry picked from commit 3056b4934e511d6f0b0a3711f15dd7a7cf233544) [no changelog] --- python/src/trezorlib/debuglink.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/python/src/trezorlib/debuglink.py b/python/src/trezorlib/debuglink.py index 75cb90bd46..bd2abc1d5b 100644 --- a/python/src/trezorlib/debuglink.py +++ b/python/src/trezorlib/debuglink.py @@ -47,6 +47,7 @@ from .client import TrezorClient from .exceptions import TrezorFailure, UnexpectedMessageError from .log import DUMP_BYTES from .messages import DebugWaitType +from .transport import Timeout if TYPE_CHECKING: from typing_extensions import Protocol @@ -502,8 +503,8 @@ class DebugLink: ) self.transport.write(msg_type, msg_bytes) - def _read(self) -> protobuf.MessageType: - ret_type, ret_bytes = self.transport.read() + def _read(self, timeout: float | None = None) -> protobuf.MessageType: + ret_type, ret_bytes = self.transport.read(timeout=timeout) LOG.log( DUMP_BYTES, f"received type {ret_type} ({len(ret_bytes)} bytes): {ret_bytes.hex()}", @@ -522,9 +523,9 @@ class DebugLink: ) return msg - def _call(self, msg: protobuf.MessageType) -> Any: + def _call(self, msg: protobuf.MessageType, timeout: float | None = None) -> Any: self._write(msg) - return self._read() + return self._read(timeout=timeout) def state(self, wait_type: DebugWaitType | None = None) -> messages.DebugLinkState: if wait_type is None: @@ -649,7 +650,13 @@ class DebugLink: if self.model is models.T1B1: return # When the call below returns, we know that `decision` has been processed in Core. - self._call(messages.DebugLinkGetState(return_empty_state=True)) + # XXX Due to a bug, the reply may get lost at the end of a workflow. + # We assume that no single input event takes more than 5 seconds to process, + # and give up waiting after that. + try: + self._call(messages.DebugLinkGetState(return_empty_state=True), timeout=5) + except Timeout as e: + LOG.warning("timeout waiting for DebugLinkState: %s", e) press_yes = _make_input_func(button=messages.DebugButton.YES) """Confirm current layout. See `_decision` for more details."""