From 0890f68c0c61a5839bea665905f571ad124dba41 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 30 Jul 2019 17:57:59 +0200 Subject: [PATCH] core: use channels to give feedback over debuglink all debug input signals are now channels, and DebugLinkDecision handler waits until the input was consumed. This means that the input events are queued; originally, if an input event arrived before the previous was consumed, the previous input would be lost. reset words and their positions are now also channels, and DebugLinkGetState can wait for their updates, if required --- common/protob/messages-debug.proto | 2 + core/src/apps/debug/__init__.py | 52 ++++++++++++++----- core/src/apps/management/common/layout.py | 7 +-- core/src/trezor/messages/DebugLinkGetState.py | 15 ++++++ .../trezorlib/messages/DebugLinkGetState.py | 15 ++++++ 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/common/protob/messages-debug.proto b/common/protob/messages-debug.proto index ff1a458c7..b308a1f4f 100644 --- a/common/protob/messages-debug.proto +++ b/common/protob/messages-debug.proto @@ -24,6 +24,8 @@ message DebugLinkDecision { * @next DebugLinkState */ message DebugLinkGetState { + optional bool wait_word_list = 1; // Trezor T only - wait until mnemonic words are shown + optional bool wait_word_pos = 2; // Trezor T only - wait until reset word position is requested } /** diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py index 7292cd51c..4e3d92486 100644 --- a/core/src/apps/debug/__init__.py +++ b/core/src/apps/debug/__init__.py @@ -4,36 +4,60 @@ if not __debug__: halt("debug mode inactive") if __debug__: - from trezor import config, loop, utils + from trezor import config, log, loop, utils from trezor.messages import MessageType from trezor.wire import register, protobuf_workflow if False: - from typing import List, Optional + from typing import Optional from trezor import wire from trezor.messages.DebugLinkDecision import DebugLinkDecision from trezor.messages.DebugLinkGetState import DebugLinkGetState from trezor.messages.DebugLinkState import DebugLinkState reset_internal_entropy = None # type: Optional[bytes] - reset_current_words = None # type: Optional[List[str]] - reset_word_index = None # type: Optional[int] + reset_current_words = loop.chan() + reset_word_index = loop.chan() - confirm_signal = loop.signal() - swipe_signal = loop.signal() - input_signal = loop.signal() + confirm_chan = loop.chan() + swipe_chan = loop.chan() + input_chan = loop.chan() + confirm_signal = confirm_chan.take + swipe_signal = swipe_chan.take + input_signal = input_chan.take async def dispatch_DebugLinkDecision( ctx: wire.Context, msg: DebugLinkDecision ) -> None: from trezor.ui import confirm, swipe + waiting_signals = [ + bool(s.putters) for s in (confirm_chan, swipe_chan, input_chan) + ] + if sum(waiting_signals) > 0: + log.warning( + __name__, + "Received new DebugLinkDecision before the previous one was handled.", + ) + log.warning( + __name__, + "received: button {}, swipe {}, input {}".format( + msg.yes_no, msg.up_down, msg.input + ), + ) + log.warning( + __name__, + "waiting: button {}, swipe {}, input {}".format(*waiting_signals), + ) + if msg.yes_no is not None: - confirm_signal.send(confirm.CONFIRMED if msg.yes_no else confirm.CANCELLED) + await confirm_chan.put( + confirm.CONFIRMED if msg.yes_no else confirm.CANCELLED + ) if msg.up_down is not None: - swipe_signal.send(swipe.SWIPE_DOWN if msg.up_down else swipe.SWIPE_UP) + await swipe_chan.put(swipe.SWIPE_DOWN if msg.up_down else swipe.SWIPE_UP) if msg.input is not None: - input_signal.send(msg.input) + await input_chan.put(msg.input) async def dispatch_DebugLinkGetState( ctx: wire.Context, msg: DebugLinkGetState @@ -45,10 +69,12 @@ if __debug__: m.mnemonic_secret = mnemonic.get_secret() m.mnemonic_type = mnemonic.get_type() m.passphrase_protection = storage.device.has_passphrase() - m.reset_word_pos = reset_word_index m.reset_entropy = reset_internal_entropy - if reset_current_words: - m.reset_word = " ".join(reset_current_words) + + if msg.wait_word_pos: + m.reset_word_pos = await reset_word_index.take() + if msg.wait_word_list: + m.reset_word = " ".join(await reset_current_words.take()) return m def boot() -> None: diff --git a/core/src/apps/management/common/layout.py b/core/src/apps/management/common/layout.py index 6bd6df1ba..e64040fb7 100644 --- a/core/src/apps/management/common/layout.py +++ b/core/src/apps/management/common/layout.py @@ -93,7 +93,7 @@ async def _confirm_word(ctx, share_index, numbered_share_words, count): # we always confirm the first (random) word index checked_index, checked_word = numbered_choices[0] if __debug__: - debug.reset_word_index = checked_index + debug.reset_word_index.publish(checked_index) # shuffle again so the confirmed word is not always the first choice random.shuffle(numbered_choices) @@ -200,7 +200,7 @@ async def _bip39_show_mnemonic(ctx, words: list): def export_displayed_words(): # export currently displayed mnemonic words into debuglink - debug.reset_current_words = [w for _, w in words[paginated.page]] + debug.reset_current_words.publish([w for _, w in words[paginated.page]]) paginated.on_change = export_displayed_words export_displayed_words() @@ -393,7 +393,8 @@ async def _slip39_show_share_words(ctx, share_index, share_words): def export_displayed_words(): # export currently displayed mnemonic words into debuglink - debug.reset_current_words = [w for _, w in word_pages[paginated.page]] + words = [w for _, w in word_pages[paginated.page]] + debug.reset_current_words.publish(words) paginated.on_change = export_displayed_words export_displayed_words() diff --git a/core/src/trezor/messages/DebugLinkGetState.py b/core/src/trezor/messages/DebugLinkGetState.py index d979eaf58..1b834fe45 100644 --- a/core/src/trezor/messages/DebugLinkGetState.py +++ b/core/src/trezor/messages/DebugLinkGetState.py @@ -12,3 +12,18 @@ if __debug__: class DebugLinkGetState(p.MessageType): MESSAGE_WIRE_TYPE = 101 + + def __init__( + self, + wait_word_list: bool = None, + wait_word_pos: bool = None, + ) -> None: + self.wait_word_list = wait_word_list + self.wait_word_pos = wait_word_pos + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('wait_word_list', p.BoolType, 0), + 2: ('wait_word_pos', p.BoolType, 0), + } diff --git a/python/trezorlib/messages/DebugLinkGetState.py b/python/trezorlib/messages/DebugLinkGetState.py index f4c24df7c..f6a1114b2 100644 --- a/python/trezorlib/messages/DebugLinkGetState.py +++ b/python/trezorlib/messages/DebugLinkGetState.py @@ -12,3 +12,18 @@ if __debug__: class DebugLinkGetState(p.MessageType): MESSAGE_WIRE_TYPE = 101 + + def __init__( + self, + wait_word_list: bool = None, + wait_word_pos: bool = None, + ) -> None: + self.wait_word_list = wait_word_list + self.wait_word_pos = wait_word_pos + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('wait_word_list', p.BoolType, 0), + 2: ('wait_word_pos', p.BoolType, 0), + }