docs(core): document why `_waiting_screen` doesn't send ButtonRequests
What changed, and why it matters
This commit only adds comments explaining existing behavior in a Trezor firmware source file. No code logic was changed, no bugs were fixed, and no security vulnerability is present in the diff.
No action needed. This is a non-functional documentation commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change is purely documentation: it adds inline comments and an assert in core/src/trezor/wire/protocol_common.py to explain why _waiting_screen does not start a ButtonRequest handler and why it uses layout.start() instead of interact(). The actual runtime behavior is unchanged except for the addition of a debug-only assert (assert layout.button_request_handler is None).
Changed components
core/src/trezor/wire/protocol_common.pyInspect captured patch +8 / −1
diff --git a/core/src/trezor/wire/protocol_common.py b/core/src/trezor/wire/protocol_common.py
index b107fcfd..8f4be82a 100644
--- a/core/src/trezor/wire/protocol_common.py
+++ b/core/src/trezor/wire/protocol_common.py
@@ -157,7 +157,13 @@ async def _waiting_screen(raise_on_cancel: type[Exception] | None) -> None:
) as obj:
# Block until the user confirmation.
# Don't use `interact` to avoid cancelling current workflow.
- await Layout(obj).get_result()
+ layout = Layout(obj)
+ layout.start()
+ # This task doesn't have access to I/O context - see `ButtonRequestHandler.join()`.
+ # Therefore, the new layout won't start its own ButtonRequest handler,
+ # avoiding interference with the existing layout (the one we are waiting for).
+ assert layout.button_request_handler is None
+ await layout.get_result()
if raise_on_cancel:
raise raise_on_cancel()
@@ -218,6 +224,7 @@ class ButtonRequestHandler:
self.box.put(None, replace=True)
# Wait for the ButtonRequest handler to finish (or user cancellation)
+ # `_waiting_screen` layout won't have an I/O context, since it runs in a separate task.
await loop.race(self.is_done, _waiting_screen(self.raise_on_cancel))
async def _handle(self, ack_callback: AckCallback) -> None:
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.