diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py index 3c3d67c0d..8d3609684 100644 --- a/core/src/apps/debug/__init__.py +++ b/core/src/apps/debug/__init__.py @@ -56,7 +56,7 @@ if __debug__: def notify_layout_change(layout: Layout) -> None: storage.current_content[:] = layout.read_content() - if storage.watch_layout_changes: + if storage.watch_layout_changes or layout_change_chan.takers: layout_change_chan.publish(storage.current_content) async def dispatch_debuglink_decision(msg: DebugLinkDecision) -> None: diff --git a/python/src/trezorlib/debuglink.py b/python/src/trezorlib/debuglink.py index dd7f5ff18..052fa3f2c 100644 --- a/python/src/trezorlib/debuglink.py +++ b/python/src/trezorlib/debuglink.py @@ -158,8 +158,8 @@ class DebugLink: def press_no(self): self.input(button=False) - def swipe_up(self): - self.input(swipe=messages.DebugSwipeDirection.UP) + def swipe_up(self, wait=False): + self.input(swipe=messages.DebugSwipeDirection.UP, wait=wait) def swipe_down(self): self.input(swipe=messages.DebugSwipeDirection.DOWN) @@ -234,13 +234,10 @@ class DebugUI: if self.input_flow is None: if br.code == messages.ButtonRequestType.PinEntry: self.debuglink.input(self.get_pin()) - elif ( - br.pages is not None - and br.page_number is not None - and br.pages > br.page_number - ): - self.debuglink.swipe_up() else: + if br.pages is not None: + for _ in range(br.pages - 1): + self.debuglink.swipe_up(wait=True) self.debuglink.press_yes() elif self.input_flow is self.INPUT_FLOW_DONE: raise AssertionError("input flow ended prematurely") diff --git a/tests/common.py b/tests/common.py index 368fc8afc..faece150e 100644 --- a/tests/common.py +++ b/tests/common.py @@ -20,7 +20,7 @@ from pathlib import Path import pytest from trezorlib import btc, tools -from trezorlib.messages import ButtonRequest, ButtonRequestType as B +from trezorlib.messages import ButtonRequestType as B # fmt: off # 1 2 3 4 5 6 7 8 9 10 11 12 @@ -188,15 +188,14 @@ def read_and_confirm_mnemonic(debug, choose_wrong=False): mnemonic = yield from read_and_confirm_mnemonic(client.debug) """ mnemonic = [] - while True: - br = yield + br = yield + for _ in range(br.pages - 1): mnemonic.extend(debug.read_reset_word().split()) - if br.page_number < br.pages: - debug.swipe_up() - else: - # last page is confirmation - debug.press_yes() - break + debug.swipe_up(wait=True) + + # last page is confirmation + mnemonic.extend(debug.read_reset_word().split()) + debug.press_yes() # check share for _ in range(3): @@ -210,15 +209,6 @@ def read_and_confirm_mnemonic(debug, choose_wrong=False): return " ".join(mnemonic) -def paging_responses(pages, code=None): - """Generate a sequence of ButtonRequests for paging through a specified number - of screens. - """ - return [ - ButtonRequest(code=code, page_number=i + 1, pages=pages) for i in range(pages) - ] - - def get_test_address(client): """Fetch a testnet address on a fixed path. Useful to make a pin/passphrase protected call, or to identify the root secret (seed+passphrase)""" diff --git a/tests/device_tests/cardano/test_sign_tx.py b/tests/device_tests/cardano/test_sign_tx.py index ba78d90d3..6d7fbd48b 100644 --- a/tests/device_tests/cardano/test_sign_tx.py +++ b/tests/device_tests/cardano/test_sign_tx.py @@ -102,13 +102,8 @@ def test_cardano_sign_tx_with_multiple_chunks(client, parameters, result): expected_responses = [ messages.PassphraseRequest(), - # XXX as many ButtonRequests as paginations. We are relying on the fact that - # there is only one fixture whose pagination is known. - # If that changes, we'll need to figure out something else. - messages.ButtonRequest(page_number=1), - messages.ButtonRequest(page_number=2), - messages.ButtonRequest(page_number=1), - messages.ButtonRequest(page_number=2), + messages.ButtonRequest(), + messages.ButtonRequest(), ] expected_responses += [ messages.CardanoSignedTxChunk(signed_tx_chunk=bytes.fromhex(signed_tx_chunk)) diff --git a/tests/device_tests/test_msg_backup_device.py b/tests/device_tests/test_msg_backup_device.py index 4aeb4273f..b44f18608 100644 --- a/tests/device_tests/test_msg_backup_device.py +++ b/tests/device_tests/test_msg_backup_device.py @@ -27,7 +27,6 @@ from ..common import ( MNEMONIC_SLIP39_ADVANCED_20, MNEMONIC_SLIP39_BASIC_20_3of6, click_through, - paging_responses, read_and_confirm_mnemonic, ) @@ -37,8 +36,6 @@ from ..common import ( def test_backup_bip39(client): assert client.features.needs_backup is True mnemonic = None - words = 12 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): nonlocal mnemonic @@ -56,9 +53,7 @@ def test_backup_bip39(client): client.set_expected_responses( [ messages.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), messages.ButtonRequest(code=B.Success), messages.Success, @@ -81,8 +76,6 @@ def test_backup_bip39(client): def test_backup_slip39_basic(client): assert client.features.needs_backup is True mnemonics = [] - words = 20 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): # 1. Checklist @@ -110,7 +103,7 @@ def test_backup_slip39_basic(client): client.set_expected_responses( [messages.ButtonRequest(code=B.ResetDevice)] * 6 # intro screens + [ - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 5 # individual shares @@ -139,8 +132,6 @@ def test_backup_slip39_basic(client): def test_backup_slip39_advanced(client): assert client.features.needs_backup is True mnemonics = [] - words = 20 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): # 1. Checklist @@ -177,7 +168,7 @@ def test_backup_slip39_advanced(client): ] * 5 # group thresholds + [ - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 25 # individual shares diff --git a/tests/device_tests/test_msg_getaddress_show.py b/tests/device_tests/test_msg_getaddress_show.py index a378622fb..957004a0e 100644 --- a/tests/device_tests/test_msg_getaddress_show.py +++ b/tests/device_tests/test_msg_getaddress_show.py @@ -190,7 +190,7 @@ def test_show_multisig_xpubs( lines1 = client.debug.wait_layout().lines assert lines1[0] == "XPUB #1 " + ("(yours)" if i == 0 else "(cosigner)") client.debug.swipe_up() - yield + lines2 = client.debug.wait_layout().lines assert lines2[0] == "XPUB #1 " + ("(yours)" if i == 0 else "(cosigner)") assert "".join(lines1[1:] + lines2[1:]) == xpubs[0] @@ -200,7 +200,7 @@ def test_show_multisig_xpubs( lines1 = client.debug.wait_layout().lines assert lines1[0] == "XPUB #2 " + ("(yours)" if i == 1 else "(cosigner)") client.debug.swipe_up() - yield + lines2 = client.debug.wait_layout().lines assert lines2[0] == "XPUB #2 " + ("(yours)" if i == 1 else "(cosigner)") assert "".join(lines1[1:] + lines2[1:]) == xpubs[1] @@ -210,7 +210,7 @@ def test_show_multisig_xpubs( lines1 = client.debug.wait_layout().lines assert lines1[0] == "XPUB #3 " + ("(yours)" if i == 2 else "(cosigner)") client.debug.swipe_up() - yield + lines2 = client.debug.wait_layout().lines assert lines2[0] == "XPUB #3 " + ("(yours)" if i == 2 else "(cosigner)") assert "".join(lines1[1:] + lines2[1:]) == xpubs[2] diff --git a/tests/device_tests/test_msg_resetdevice_bip39_t2.py b/tests/device_tests/test_msg_resetdevice_bip39_t2.py index 1f033140e..727926bad 100644 --- a/tests/device_tests/test_msg_resetdevice_bip39_t2.py +++ b/tests/device_tests/test_msg_resetdevice_bip39_t2.py @@ -27,7 +27,6 @@ from ..common import ( MNEMONIC12, click_through, generate_entropy, - paging_responses, read_and_confirm_mnemonic, ) @@ -35,8 +34,6 @@ EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2 def reset_device(client, strength): - words = strength // 32 * 3 - mnemonic_pages = ((words + 3) // 4) + 1 mnemonic = None def input_flow(): @@ -67,9 +64,7 @@ def reset_device(client, strength): proto.EntropyRequest(), proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.Success), proto.ButtonRequest(code=B.Success), proto.Success, @@ -124,8 +119,6 @@ class TestMsgResetDeviceT2: def test_reset_device_pin(self, client): mnemonic = None strength = 256 # 24 words - words = strength // 32 * 3 - mnemonic_pages = (words // 4) + 1 def input_flow(): nonlocal mnemonic @@ -182,9 +175,7 @@ class TestMsgResetDeviceT2: proto.EntropyRequest(), proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.Success), proto.ButtonRequest(code=B.Success), proto.Success, @@ -223,8 +214,6 @@ class TestMsgResetDeviceT2: def test_reset_failed_check(self, client): mnemonic = None strength = 256 # 24 words - words = strength // 32 * 3 - mnemonic_pages = (words // 4) + 1 def input_flow(): nonlocal mnemonic @@ -264,11 +253,9 @@ class TestMsgResetDeviceT2: proto.EntropyRequest(), proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [proto.ButtonRequest(code=B.ResetDevice)] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.Success), proto.ButtonRequest(code=B.Success), proto.Success, diff --git a/tests/device_tests/test_msg_resetdevice_slip39_advanced.py b/tests/device_tests/test_msg_resetdevice_slip39_advanced.py index 240159038..7d4836e65 100644 --- a/tests/device_tests/test_msg_resetdevice_slip39_advanced.py +++ b/tests/device_tests/test_msg_resetdevice_slip39_advanced.py @@ -23,12 +23,7 @@ from trezorlib import device, messages as proto from trezorlib.exceptions import TrezorFailure from trezorlib.messages import BackupType, ButtonRequestType as B -from ..common import ( - click_through, - generate_entropy, - paging_responses, - read_and_confirm_mnemonic, -) +from ..common import click_through, generate_entropy, read_and_confirm_mnemonic EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2 @@ -39,8 +34,6 @@ class TestMsgResetDeviceT2: @pytest.mark.setup_client(uninitialized=True) def test_reset_device_slip39_advanced(self, client): strength = 128 - word_count = 20 - mnemonic_page_count = (word_count // 4) + 1 member_threshold = 3 all_mnemonics = [] @@ -101,7 +94,7 @@ class TestMsgResetDeviceT2: ] + [ # individual mnemonic - *paging_responses(mnemonic_page_count, code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.Success), ] * (5 * 5) # groups * shares diff --git a/tests/device_tests/test_msg_resetdevice_slip39_basic.py b/tests/device_tests/test_msg_resetdevice_slip39_basic.py index 00d9760e1..501ec57ee 100644 --- a/tests/device_tests/test_msg_resetdevice_slip39_basic.py +++ b/tests/device_tests/test_msg_resetdevice_slip39_basic.py @@ -28,16 +28,11 @@ from ..common import ( EXTERNAL_ENTROPY, click_through, generate_entropy, - paging_responses, read_and_confirm_mnemonic, ) def reset_device(client, strength): - # per SLIP-39: strength in bits, rounded up to nearest multiple of 10, plus 70 bits - # of metadata, split into 10-bit words - word_count = ((strength + 9) // 10) + 7 - mnemonic_pages = ((word_count + 3) // 4) + 1 member_threshold = 3 all_mnemonics = [] @@ -84,7 +79,7 @@ def reset_device(client, strength): ] + [ # individual mnemonic - *paging_responses(mnemonic_pages, code=B.ResetDevice), + proto.ButtonRequest(code=B.ResetDevice), proto.ButtonRequest(code=B.Success), ] * 5 # number of shares diff --git a/tests/device_tests/test_msg_signmessage.py b/tests/device_tests/test_msg_signmessage.py index 5483cd77c..87d818950 100644 --- a/tests/device_tests/test_msg_signmessage.py +++ b/tests/device_tests/test_msg_signmessage.py @@ -242,12 +242,8 @@ def test_signmessage_pagination(client, message): # start assuming there was a word break; this avoids prepending space at start word_break = True - page = 0 - while True: - br = yield - assert br.page_number == page + 1 - page = br.page_number - + br = yield + for i in range(br.pages): layout = client.debug.wait_layout() for line in layout.lines[1:]: if line == "-": @@ -261,11 +257,10 @@ def test_signmessage_pagination(client, message): # attach with space message_read += " " + line - if page < br.pages: + if i < br.pages - 1: client.debug.swipe_up() - else: - client.debug.press_yes() - break + + client.debug.press_yes() with client: client.set_input_flow(input_flow) diff --git a/tests/device_tests/test_msg_signtx_replacement.py b/tests/device_tests/test_msg_signtx_replacement.py index d3a59de4f..29e9bcd6b 100644 --- a/tests/device_tests/test_msg_signtx_replacement.py +++ b/tests/device_tests/test_msg_signtx_replacement.py @@ -505,6 +505,7 @@ def test_p2wpkh_in_p2sh_fee_bump_from_external(client): orig_index=0, ) + t1 = client.features.model == "1" with client: client.set_expected_responses( [ @@ -517,7 +518,7 @@ def test_p2wpkh_in_p2sh_fee_bump_from_external(client): request_output(0), request_orig_output(0, TXHASH_334cd7), messages.ButtonRequest(code=B.ConfirmOutput), - messages.ButtonRequest(code=B.ConfirmOutput), + (t1, messages.ButtonRequest(code=B.ConfirmOutput)), request_orig_output(1, TXHASH_334cd7), messages.ButtonRequest(code=B.SignTx), request_input(0), diff --git a/tests/device_tests/test_reset_backup.py b/tests/device_tests/test_reset_backup.py index 4e6f08224..6b6b343f7 100644 --- a/tests/device_tests/test_reset_backup.py +++ b/tests/device_tests/test_reset_backup.py @@ -23,18 +23,11 @@ from shamir_mnemonic import shamir from trezorlib import device, messages from trezorlib.messages import BackupType, ButtonRequestType as B -from ..common import ( - EXTERNAL_ENTROPY, - click_through, - paging_responses, - read_and_confirm_mnemonic, -) +from ..common import EXTERNAL_ENTROPY, click_through, read_and_confirm_mnemonic def backup_flow_bip39(client): mnemonic = None - words = 12 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): nonlocal mnemonic @@ -59,9 +52,7 @@ def backup_flow_bip39(client): client.set_expected_responses( [ messages.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), messages.ButtonRequest(code=B.Success), messages.Success, @@ -76,8 +67,6 @@ def backup_flow_bip39(client): def backup_flow_slip39_basic(client): mnemonics = [] - words = 20 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): # 1. Checklist @@ -105,7 +94,7 @@ def backup_flow_slip39_basic(client): client.set_expected_responses( [messages.ButtonRequest(code=B.ResetDevice)] * 6 # intro screens + [ - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 5 # individual shares @@ -124,8 +113,6 @@ def backup_flow_slip39_basic(client): def backup_flow_slip39_advanced(client): mnemonics = [] - words = 20 - mnemonic_pages = ((words + 3) // 4) + 1 def input_flow(): # 1. Confirm Reset @@ -166,7 +153,7 @@ def backup_flow_slip39_advanced(client): ] * 5 # group thresholds + [ - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 25 # individual shares diff --git a/tests/device_tests/test_reset_recovery_bip39.py b/tests/device_tests/test_reset_recovery_bip39.py index 2eda9ccb0..7be9dd7e0 100644 --- a/tests/device_tests/test_reset_recovery_bip39.py +++ b/tests/device_tests/test_reset_recovery_bip39.py @@ -23,12 +23,7 @@ from trezorlib import btc, device, messages from trezorlib.messages import BackupType, ButtonRequestType as B from trezorlib.tools import parse_path -from ..common import ( - EXTERNAL_ENTROPY, - click_through, - paging_responses, - read_and_confirm_mnemonic, -) +from ..common import EXTERNAL_ENTROPY, click_through, read_and_confirm_mnemonic @pytest.mark.skip_t1 @@ -44,8 +39,6 @@ def test_reset_recovery(client): def reset(client, strength=128, skip_backup=False): - words = strength // 32 * 3 - mnemonic_pages = ((words + 3) // 4) + 1 mnemonic = None def input_flow(): @@ -77,9 +70,7 @@ def reset(client, strength=128, skip_backup=False): messages.EntropyRequest(), messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.ResetDevice), - ] - + paging_responses(mnemonic_pages, code=B.ResetDevice) - + [ + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), messages.ButtonRequest(code=B.Success), messages.Success, diff --git a/tests/device_tests/test_reset_recovery_slip39_advanced.py b/tests/device_tests/test_reset_recovery_slip39_advanced.py index 02133de6e..b47c04e99 100644 --- a/tests/device_tests/test_reset_recovery_slip39_advanced.py +++ b/tests/device_tests/test_reset_recovery_slip39_advanced.py @@ -25,7 +25,6 @@ from trezorlib.tools import parse_path from ..common import ( EXTERNAL_ENTROPY, click_through, - paging_responses, read_and_confirm_mnemonic, recovery_enter_shares, ) @@ -60,10 +59,6 @@ def test_reset_recovery(client): def reset(client, strength=128): all_mnemonics = [] - # per SLIP-39: strength in bits, rounded up to nearest multiple of 10, plus 70 bits - # of metadata, split into 10-bit words - word_count = ((strength + 9) // 10) + 7 - mnemonic_pages = ((word_count + 3) // 4) + 1 def input_flow(): # 1. Confirm Reset @@ -122,7 +117,7 @@ def reset(client, strength=128): ] + [ # individual mnemonic - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * (5 * 5) # groups * shares diff --git a/tests/device_tests/test_reset_recovery_slip39_basic.py b/tests/device_tests/test_reset_recovery_slip39_basic.py index 37b69b614..e6045ccfc 100644 --- a/tests/device_tests/test_reset_recovery_slip39_basic.py +++ b/tests/device_tests/test_reset_recovery_slip39_basic.py @@ -23,12 +23,7 @@ from trezorlib import btc, device, messages from trezorlib.messages import BackupType, ButtonRequestType as B from trezorlib.tools import parse_path -from ..common import ( - click_through, - paging_responses, - read_and_confirm_mnemonic, - recovery_enter_shares, -) +from ..common import click_through, read_and_confirm_mnemonic, recovery_enter_shares EXTERNAL_ENTROPY = b"zlutoucky kun upel divoke ody" * 2 MOCK_OS_URANDOM = mock.Mock(return_value=EXTERNAL_ENTROPY) @@ -51,10 +46,6 @@ def test_reset_recovery(client): def reset(client, strength=128): all_mnemonics = [] - # per SLIP-39: strength in bits, rounded up to nearest multiple of 10, plus 70 bits - # of metadata, split into 10-bit words - word_count = ((strength + 9) // 10) + 7 - mnemonic_pages = ((word_count + 3) // 4) + 1 def input_flow(): # 1. Confirm Reset @@ -98,7 +89,7 @@ def reset(client, strength=128): ] + [ # individual mnemonic - *paging_responses(mnemonic_pages, code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), messages.ButtonRequest(code=B.Success), ] * 5 # number of shares