test(core): add T3T1 support

[no changelog]
pull/3601/head
Martin Milata 2 months ago
parent ebb480ef29
commit 73a7223e7b

@ -13,8 +13,9 @@ env:
PULL_COMMENT: |
|core UI changes|device test|click test|persistence test|
|---------------|-----------|----------|----------------|
|Model T |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/master_diff.html))||
|Model Safe 3 |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_device_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_persistence_test/master_diff.html))||
|T2T1 Model T |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_device_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_click_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-core_persistence_test/master_diff.html))||
|T2B1 Safe 3 |[#3280](https://github.com/trezor/trezor-firmware/issues/3280) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-core_click_test/master_diff.html)) |[#2724](https://github.com/trezor/trezor-firmware/issues/2724) ||
|T3T1 |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_device_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_click_test/master_diff.html)) |[test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-core_persistence_test/master_diff.html))||
|All |[main](https://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }}/index.html)([screens](https://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }}/master_diff.html)) ||
jobs:

@ -170,14 +170,14 @@ if __debug__:
# Incrementing the counter for last events so we know what to await
debug_events.last_event += 1
# TT click on specific coordinates, with possible hold
# Touchscreen devices click on specific coordinates, with possible hold
if (
x is not None
and y is not None
and utils.INTERNAL_MODEL in ("T2T1", "T3T1", "D001")
):
click_chan.publish((debug_events.last_event, x, y, msg.hold_ms))
# TR press specific button
# Button devices press specific button
elif msg.physical_button is not None and utils.INTERNAL_MODEL in ("T2B1",):
button_chan.publish(
(debug_events.last_event, msg.physical_button, msg.hold_ms)

@ -319,5 +319,5 @@ class TestNemHDNode(unittest.TestCase):
if __name__ == "__main__":
if not utils.MODEL_IS_T2B1:
if utils.INTERNAL_MODEL == "T2T1":
unittest.main()

@ -109,6 +109,7 @@ Tests can be run only for specific models - it is done by disallowing the tests
`@pytest.mark.skip_t1`
`@pytest.mark.skip_t2`
`@pytest.mark.skip_tr`
`@pytest.mark.skip_t3t1`
are valid markers to skip current test for T1, TT and TR respectively.
[pytest-random-order]: https://pypi.org/project/pytest-random-order/

@ -44,7 +44,7 @@ from typing import (
from mnemonic import Mnemonic
from typing_extensions import Literal
from . import mapping, messages, protobuf
from . import mapping, messages, models, protobuf
from .client import TrezorClient
from .exceptions import TrezorFailure
from .log import DUMP_BYTES
@ -368,7 +368,7 @@ class DebugLink:
self.mapping = mapping.DEFAULT_MAPPING
# To be set by TrezorClientDebugLink (is not known during creation time)
self.model: Optional[str] = None
self.model: Optional[models.TrezorModel] = None
self.version: Tuple[int, int, int] = (0, 0, 0)
# Where screenshots are being saved
@ -452,7 +452,7 @@ class DebugLink:
def reset_debug_events(self) -> None:
# Only supported on TT and above certain version
if self.model in ("T", "Safe 3") and not self.legacy_debug:
if (self.model is not models.T1B1) and not self.legacy_debug:
return self._call(messages.DebugLinkResetDebugEvents())
return None
@ -691,7 +691,7 @@ class DebugLink:
) -> None:
self.screenshot_recording_dir = directory
# Different recording logic between core and legacy
if self.model in ("T", "Safe 3"):
if self.model is not models.T1B1:
self._call(
messages.DebugLinkRecordScreen(
target_directory=directory, refresh_index=refresh_index
@ -705,7 +705,7 @@ class DebugLink:
def stop_recording(self) -> None:
self.screenshot_recording_dir = None
# Different recording logic between TT and T1
if self.model in ("T", "Safe 3"):
if self.model is not models.T1B1:
self._call(messages.DebugLinkRecordScreen(target_directory=None))
else:
self.t1_take_screenshots = False
@ -732,7 +732,7 @@ class DebugLink:
TT handles them differently, see debuglink.start_recording.
"""
if self.model == "1" and self.t1_take_screenshots:
if self.model is models.T1B1 and self.t1_take_screenshots:
self.save_screenshot_for_t1()
def save_screenshot_for_t1(self) -> None:
@ -962,7 +962,7 @@ class TrezorClientDebugLink(TrezorClient):
# So that we can choose right screenshotting logic (T1 vs TT)
# and know the supported debug capabilities
self.debug.model = self.features.model
self.debug.model = self.model
self.debug.version = self.version
def reset_debug_features(self) -> None:

@ -3,6 +3,8 @@ from __future__ import annotations
from enum import Enum
from typing import TYPE_CHECKING
from trezorlib import models
from .. import buttons
from .. import translations as TR
@ -44,9 +46,9 @@ def get_char_category(char: str) -> PassphraseCategory:
def go_next(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None:
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
return debug.click(buttons.OK, wait=wait) # type: ignore
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
return debug.press_right(wait=wait) # type: ignore
else:
raise RuntimeError("Unknown model")
@ -55,9 +57,10 @@ def go_next(debug: "DebugLink", wait: bool = False) -> "LayoutContent" | None:
def go_back(
debug: "DebugLink", wait: bool = False, r_middle: bool = False
) -> "LayoutContent" | None:
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
return debug.click(buttons.CANCEL, wait=wait) # type: ignore
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
if r_middle:
return debug.press_middle(wait=wait) # type: ignore
else:

@ -1,5 +1,7 @@
from typing import TYPE_CHECKING
from trezorlib import models
from .. import buttons
from .. import translations as TR
from .common import get_possible_btn_texts, go_next
@ -16,13 +18,13 @@ DELETE_BTN_TEXTS = get_possible_btn_texts("inputs__delete") + get_possible_btn_t
def enter_word(
debug: "DebugLink", word: str, is_slip39: bool = False
) -> "LayoutContent":
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
typed_word = word[:4]
for coords in buttons.type_word(typed_word, is_slip39=is_slip39):
debug.click(coords)
return debug.click(buttons.CONFIRM_WORD, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
letter_index = 0
layout = debug.read_layout()
@ -47,9 +49,9 @@ def enter_word(
def confirm_recovery(debug: "DebugLink") -> None:
layout = debug.wait_layout()
TR.assert_equals(layout.title(), "recovery__title")
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right(wait=True)
debug.press_right()
@ -60,7 +62,7 @@ def select_number_of_words(
if wait:
debug.wait_layout()
TR.assert_equals(debug.read_layout().text_content(), "recovery__num_of_words")
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
# click the number
word_option_offset = 6
word_options = (12, 18, 20, 24, 33)
@ -69,7 +71,7 @@ def select_number_of_words(
) # raises if num of words is invalid
coords = buttons.grid34(index % 3, index // 3)
layout = debug.click(coords, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
layout = debug.press_right(wait=True)
TR.assert_equals(layout.title(), "word_count__title")
@ -92,7 +94,7 @@ def enter_share(
debug: "DebugLink", share: str, is_first: bool = True
) -> "LayoutContent":
TR.assert_in(debug.read_layout().title(), "recovery__title_recover")
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
layout = debug.wait_layout()
for _ in range(layout.page_count()):
layout = debug.press_right(wait=True)
@ -146,11 +148,11 @@ def enter_seed_previous_correct(
if go_back:
go_back = False
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.swipe_right(wait=True)
for _ in range(len(bad_word)):
debug.click(buttons.RECOVERY_DELETE, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
layout = debug.read_layout()
while layout.get_middle_choice() not in DELETE_BTN_TEXTS:
@ -177,9 +179,9 @@ def enter_seed_previous_correct(
def prepare_enter_seed(debug: "DebugLink") -> None:
TR.assert_in(debug.read_layout().text_content(), "recovery__enter_backup")
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right(wait=True)
TR.assert_equals(debug.read_layout().title(), "recovery__title_recover")
debug.press_right()

@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
from shamir_mnemonic import shamir # type: ignore
from trezorlib import messages
from trezorlib import messages, models
from .. import buttons
from .. import translations as TR
@ -17,17 +17,17 @@ def confirm_new_wallet(debug: "DebugLink") -> None:
debug.read_layout().title(),
["reset__title_create_wallet", "reset__title_create_wallet_shamir"],
)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right(wait=True)
debug.press_right(wait=True)
def confirm_read(debug: "DebugLink", middle_r: bool = False) -> None:
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
page_count = debug.read_layout().page_count()
if page_count > 1:
for _ in range(page_count - 1):
@ -39,12 +39,12 @@ def confirm_read(debug: "DebugLink", middle_r: bool = False) -> None:
def set_selection(debug: "DebugLink", button: tuple[int, int], diff: int) -> None:
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
assert "NumberInputDialog" in debug.read_layout().all_components()
for _ in range(diff):
debug.click(button)
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
layout = debug.read_layout()
if layout.title() in TR.translate(
"reset__title_number_of_shares"
@ -66,7 +66,7 @@ def read_words(
) -> list[str]:
words: list[str] = []
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
debug.press_right(wait=True)
# Swiping through all the pages and loading the words
@ -75,14 +75,14 @@ def read_words(
words.extend(layout.seed_words())
layout = debug.swipe_up(wait=True)
assert layout is not None
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
words.extend(layout.seed_words())
# There is hold-to-confirm button
if do_htc:
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click_hold(buttons.OK, hold_ms=1500)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right_htc(1200)
else:
# It would take a very long time to test 16-of-16 with doing 1500 ms HTC after
@ -94,7 +94,7 @@ def read_words(
def confirm_words(debug: "DebugLink", words: list[str]) -> None:
layout = debug.wait_layout()
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
TR.assert_template(layout.text_content(), "reset__select_word_x_of_y_template")
for _ in range(3):
# "Select word 3 of 20"
@ -109,7 +109,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None:
wanted_word = words[word_pos - 1].lower()
button_pos = btn_texts.index(wanted_word)
layout = debug.click(buttons.RESET_WORD_CHECK[button_pos], wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
TR.assert_in(layout.text_content(), "reset__select_correct_word")
layout = debug.press_right(wait=True)
for _ in range(3):

@ -20,7 +20,7 @@ from typing import TYPE_CHECKING
import pytest
from trezorlib import btc, device, exceptions, messages
from trezorlib import btc, device, exceptions, messages, models
from trezorlib.protobuf import MessageType
from trezorlib.tools import parse_path
@ -102,12 +102,12 @@ def test_autolock_interrupts_signing(device_handler: "BackgroundDeviceHandler"):
in debug.wait_layout().text_content().replace(" ", "")
)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
layout = debug.click(buttons.OK, wait=True)
TR.assert_in(layout.text_content(), "send__total_amount")
assert "0.0039 BTC" in layout.text_content()
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right(wait=True)
layout = debug.press_right(wait=True)
TR.assert_in(layout.text_content(), "send__total_amount")
@ -149,12 +149,12 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa
in debug.wait_layout().text_content().replace(" ", "")
)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
layout = debug.click(buttons.OK, wait=True)
TR.assert_in(layout.text_content(), "send__total_amount")
assert "0.0039 BTC" in layout.text_content()
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_right(wait=True)
layout = debug.press_right(wait=True)
TR.assert_in(layout.text_content(), "send__total_amount")
@ -168,9 +168,9 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa
with device_handler.client:
device_handler.client.set_filter(messages.TxAck, sleepy_filter)
# confirm transaction
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_middle()
signatures, tx = device_handler.result()
@ -190,17 +190,17 @@ def test_autolock_passphrase_keyboard(device_handler: "BackgroundDeviceHandler")
assert "PassphraseKeyboard" in debug.wait_layout().all_components()
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
# Going into the selected character category
debug.press_middle()
# enter passphrase - slowly
# keep clicking for long enough to trigger the autolock if it incorrectly ignored key presses
for _ in range(math.ceil(11 / 1.5)):
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
# click at "j"
debug.click(CENTER_BUTTON)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
# just go right
# NOTE: because of passphrase randomization it would be a pain to input
# a specific passphrase, which is not in scope for this test.
@ -208,9 +208,9 @@ def test_autolock_passphrase_keyboard(device_handler: "BackgroundDeviceHandler")
time.sleep(1.5)
# Send the passphrase to the client (TT has it clicked already, TR needs to input it)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.OK, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.input("j" * 8, wait=True)
# address corresponding to "jjjjjjjj" passphrase
@ -227,16 +227,16 @@ def test_autolock_interrupts_passphrase(device_handler: "BackgroundDeviceHandler
assert "PassphraseKeyboard" in debug.wait_layout().all_components()
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
# Going into the selected character category
debug.press_middle()
# enter passphrase - slowly
# autolock must activate even if we pressed some buttons
for _ in range(math.ceil(6 / 1.5)):
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(CENTER_BUTTON)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_middle()
time.sleep(1.5)
@ -267,7 +267,7 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle
layout = unlock_dry_run(debug)
TR.assert_in(debug.wait_layout().text_content(), "recovery__num_of_words")
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
debug.press_right(wait=True)
# wait for autolock to trigger
@ -300,10 +300,10 @@ def test_dryrun_locks_at_word_entry(device_handler: "BackgroundDeviceHandler"):
# select 20 words
recovery.select_number_of_words(debug, 20)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
layout = debug.click(buttons.OK, wait=True)
assert layout.main_component() == "MnemonicKeyboard"
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
layout = debug.press_right(wait=True)
assert "MnemonicKeyboard" in layout.all_components()
@ -326,7 +326,7 @@ def test_dryrun_enter_word_slowly(device_handler: "BackgroundDeviceHandler"):
# select 20 words
recovery.select_number_of_words(debug, 20)
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
layout = debug.click(buttons.OK, wait=True)
assert layout.main_component() == "MnemonicKeyboard"
@ -337,7 +337,7 @@ def test_dryrun_enter_word_slowly(device_handler: "BackgroundDeviceHandler"):
layout = debug.click(buttons.CONFIRM_WORD, wait=True)
# should not have locked, even though we took 9 seconds to type each letter
assert layout.main_component() == "MnemonicKeyboard"
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
layout = debug.press_right(wait=True)
assert "MnemonicKeyboard" in layout.all_components()

@ -19,6 +19,8 @@ from typing import TYPE_CHECKING
import pytest
from trezorlib import models
from .. import buttons, common
if TYPE_CHECKING:
@ -32,11 +34,21 @@ PIN4 = "1234"
def test_hold_to_lock(device_handler: "BackgroundDeviceHandler"):
debug = device_handler.debuglink()
short_duration = 1000 if debug.model == "T" else 500
lock_duration = 3500 if debug.model == "T" else 1200
short_duration = {
models.T1B1: 500,
models.T2B1: 500,
models.T2T1: 1000,
models.T3T1: 1000,
}[debug.model]
lock_duration = {
models.T1B1: 1200,
models.T2B1: 1200,
models.T2T1: 3500,
models.T3T1: 3500,
}[debug.model]
def hold(duration: int, wait: bool = True) -> None:
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
debug.press_right_htc(hold_ms=duration)
else:
debug.input(x=13, y=37, hold_ms=duration, wait=wait)
@ -63,7 +75,7 @@ def test_hold_to_lock(device_handler: "BackgroundDeviceHandler"):
assert device_handler.features().unlocked is False
# unlock by touching
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
# Doing a short HTC to simulate a click
debug.press_right_htc(hold_ms=100)
layout = debug.wait_layout()

@ -36,7 +36,7 @@ if TYPE_CHECKING:
from ..device_handler import BackgroundDeviceHandler
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_t2]
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_t2, pytest.mark.skip_t3t1]
# Testing the maximum length is really 50
# TODO: show some UI message when length reaches 50?

@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Generator
import pytest
from trezorlib import device, exceptions
from trezorlib import device, exceptions, models
from .. import buttons
from .. import translations as TR
@ -96,9 +96,9 @@ def prepare(
# Set new PIN
device_handler.run(device.change_pin) # type: ignore
TR.assert_in(debug.wait_layout().text_content(), "pin__turn_on")
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
go_next(debug)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
go_next(debug, wait=True)
go_next(debug, wait=True)
go_next(debug, wait=True)
@ -117,7 +117,7 @@ def prepare(
_input_see_confirm(debug, old_pin)
TR.assert_in(debug.wait_layout().text_content(), "wipe_code__turn_on")
go_next(debug, wait=True)
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
go_next(debug, wait=True)
go_next(debug, wait=True)
go_next(debug, wait=True)
@ -141,13 +141,13 @@ def _input_pin(debug: "DebugLink", pin: str, check: bool = False) -> None:
if check:
before = debug.read_layout().pin()
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
digits_order = debug.read_layout().tt_pin_digits_order()
for digit in pin:
digit_index = digits_order.index(digit)
coords = buttons.pin_passphrase_index(digit_index)
debug.click(coords, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
for digit in pin:
navigate_to_action_and_press(debug, digit, TR_PIN_ACTIONS)
@ -158,9 +158,9 @@ def _input_pin(debug: "DebugLink", pin: str, check: bool = False) -> None:
def _see_pin(debug: "DebugLink") -> None:
"""Navigate to "SHOW" and press it"""
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.TOP_ROW, wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
navigate_to_action_and_press(debug, SHOW, TR_PIN_ACTIONS)
@ -170,9 +170,9 @@ def _delete_pin(debug: "DebugLink", digits_to_delete: int, check: bool = True) -
before = debug.read_layout().pin()
for _ in range(digits_to_delete):
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.pin_passphrase_grid(9), wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS)
if check:
@ -182,9 +182,9 @@ def _delete_pin(debug: "DebugLink", digits_to_delete: int, check: bool = True) -
def _delete_all(debug: "DebugLink", check: bool = True) -> None:
"""Navigate to "DELETE" and hold it until all digits are deleted"""
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click_hold(buttons.pin_passphrase_grid(9), hold_ms=1500)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
navigate_to_action_and_press(debug, DELETE, TR_PIN_ACTIONS, hold_ms=1000)
if check:
@ -201,9 +201,9 @@ def _cancel_pin(debug: "DebugLink") -> None:
def _confirm_pin(debug: "DebugLink") -> None:
"""Navigate to "ENTER" and press it"""
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
debug.click(buttons.pin_passphrase_grid(11), wait=True)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
navigate_to_action_and_press(debug, ENTER, TR_PIN_ACTIONS)
@ -216,7 +216,7 @@ def _input_see_confirm(debug: "DebugLink", pin: str) -> None:
def _enter_two_times(debug: "DebugLink", pin1: str, pin2: str) -> None:
_input_see_confirm(debug, pin1)
if debug.model == "Safe 3":
if debug.model in (models.T2B1,):
# Please re-enter
go_next(debug, wait=True)
@ -306,10 +306,10 @@ def test_pin_setup(device_handler: "BackgroundDeviceHandler"):
def test_pin_setup_mismatch(device_handler: "BackgroundDeviceHandler"):
with PIN_CANCELLED, prepare(device_handler, Situation.PIN_SETUP) as debug:
_enter_two_times(debug, "1", "2")
if debug.model == "T":
if debug.model in (models.T2T1, models.T3T1):
go_next(debug)
_cancel_pin(debug)
elif debug.model == "Safe 3":
elif debug.model in (models.T2B1,):
debug.press_middle()
debug.press_no()

@ -30,8 +30,8 @@ if TYPE_CHECKING:
from ..device_handler import BackgroundDeviceHandler
# TR-only
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_t2]
# T2B1-only
pytestmark = [pytest.mark.skip_t1, pytest.mark.skip_t2, pytest.mark.skip_t3t1]
@contextmanager

@ -23,7 +23,7 @@ from unittest import mock
import pytest
from trezorlib import btc, messages, tools
from trezorlib import btc, messages, models, tools
if TYPE_CHECKING:
from _pytest.mark.structures import MarkDecorator
@ -89,12 +89,14 @@ def parametrize_using_common_fixtures(*paths: str) -> "MarkDecorator":
skip_models = test.get("skip_models", [])
skip_marks = []
for skip_model in skip_models:
if skip_model == "t1":
if skip_model in ("t1", "t1b1"):
skip_marks.append(pytest.mark.skip_t1)
if skip_model == "t2":
if skip_model in ("t2", "t2t1"):
skip_marks.append(pytest.mark.skip_t2)
if skip_model == "tr":
if skip_model in ("tr", "t2b1"):
skip_marks.append(pytest.mark.skip_tr)
if skip_model == "t3t1":
skip_marks.append(pytest.mark.skip_t3t1)
tests.append(
pytest.param(
@ -173,10 +175,12 @@ def read_and_confirm_mnemonic(
debug: "DebugLink", choose_wrong: bool = False
) -> Generator[None, "ButtonRequest", Optional[str]]:
# TODO: these are very similar, reuse some code
if debug.model == "T":
if debug.model is models.T2T1:
mnemonic = yield from read_and_confirm_mnemonic_tt(debug, choose_wrong)
elif debug.model == "Safe 3":
elif debug.model is models.T2B1:
mnemonic = yield from read_and_confirm_mnemonic_tr(debug, choose_wrong)
elif debug.model is models.T3T1:
mnemonic = yield from read_and_confirm_mnemonic_tt(debug, choose_wrong)
else:
raise ValueError(f"Unknown model: {debug.model}")
@ -316,3 +320,7 @@ def swipe_till_the_end(debug: "DebugLink", br: messages.ButtonRequest) -> None:
if br.pages is not None:
for _ in range(br.pages - 1):
debug.swipe_up()
def is_core(client: "Client") -> bool:
return client.model in (models.T2T1, models.T2B1, models.T3T1)

@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Generator, Iterator
import pytest
import xdist
from trezorlib import debuglink, log
from trezorlib import debuglink, log, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.device import apply_settings
from trezorlib.device import wipe as wipe_device
@ -207,6 +207,11 @@ def client(
and _raw_client.features.model == "Safe 3"
):
pytest.skip("Test excluded on Trezor R")
if (
request.node.get_closest_marker("skip_t3t1")
and _raw_client.model is models.T3T1
):
pytest.skip("Test excluded on Trezor T3T1")
sd_marker = request.node.get_closest_marker("sd_card")
if sd_marker and not _raw_client.features.sd_card_present:
@ -390,6 +395,7 @@ def pytest_configure(config: "Config") -> None:
config.addinivalue_line("markers", "skip_t1: skip the test on Trezor One")
config.addinivalue_line("markers", "skip_t2: skip the test on Trezor T")
config.addinivalue_line("markers", "skip_tr: skip the test on Trezor R")
config.addinivalue_line("markers", "skip_t3t1: skip the test on Trezor T3T1")
config.addinivalue_line(
"markers", "experimental: enable experimental features on Trezor"
)

@ -23,6 +23,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .payment_req import make_coinjoin_request
from .signtx import (
@ -453,7 +454,6 @@ def test_sign_tx_spend(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
messages.ButtonRequest(code=B.Other),
@ -462,7 +462,7 @@ def test_sign_tx_spend(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
@ -528,7 +528,6 @@ def test_sign_tx_migration(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
messages.ButtonRequest(code=B.Other),
@ -537,7 +536,7 @@ def test_sign_tx_migration(client: Client):
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_2cc3c1),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -72,14 +73,13 @@ def test_send_bch_change(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_bc37c2),
@ -125,14 +125,13 @@ def test_send_bch_nochange(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_502e85),
@ -184,14 +183,13 @@ def test_send_bch_oldaddr(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_502e85),
@ -255,7 +253,6 @@ def test_attack_change_input(client: Client):
return msg
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_filter(messages.TxAck, attack_processor)
client.set_expected_responses(
[
@ -263,7 +260,7 @@ def test_attack_change_input(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_bd32ff),
@ -331,13 +328,12 @@ def test_send_bch_multisig_wrongchange(client: Client):
amount=23_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_062fbd),
@ -400,13 +396,12 @@ def test_send_bch_multisig_change(client: Client):
amount=24_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -445,7 +440,7 @@ def test_send_bch_multisig_change(client: Client):
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -502,14 +497,13 @@ def test_send_bch_external_presigned(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_502e85),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path, tx_hash
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import request_finished, request_input, request_meta, request_output
@ -71,14 +72,13 @@ def test_send_bitcoin_gold_change(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_6f0398),
@ -125,14 +125,13 @@ def test_send_bitcoin_gold_nochange(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_6f0398),
@ -195,7 +194,6 @@ def test_attack_change_input(client: Client):
return msg
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_filter(messages.TxAck, attack_processor)
client.set_expected_responses(
[
@ -203,7 +201,7 @@ def test_attack_change_input(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_6f0398),
@ -257,13 +255,12 @@ def test_send_btg_multisig_change(client: Client):
amount=1_252_382_934 - 24_000 - 1_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -302,7 +299,7 @@ def test_send_btg_multisig_change(client: Client):
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -351,16 +348,15 @@ def test_send_p2sh(client: Client):
amount=1_252_382_934 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_db7239),
@ -405,13 +401,12 @@ def test_send_p2sh_witness_change(client: Client):
amount=1_252_382_934 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -466,13 +461,12 @@ def test_send_multisig_1(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_7f1f6b),
@ -495,7 +489,7 @@ def test_send_multisig_1(client: Client):
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_7f1f6b),
@ -584,14 +578,13 @@ def test_send_btg_external_presigned(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_6f0398),

@ -20,6 +20,7 @@ from trezorlib import btc, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
request_extra_data,
@ -57,13 +58,12 @@ def test_send_dash(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(inp1.prev_hash),
@ -105,14 +105,13 @@ def test_send_dash_dip2_input(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(inp1.prev_hash),

@ -20,6 +20,7 @@ from trezorlib import btc, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import request_finished, request_input, request_meta, request_output
@ -49,7 +50,12 @@ FAKE_TXHASH_51bc9c = bytes.fromhex(
"51bc9c71f10a81eef3caedb5333062eb4b1f70998adf02916fe98fdc04c572e8"
)
pytestmark = [pytest.mark.altcoin, pytest.mark.decred, pytest.mark.skip_tr]
pytestmark = [
pytest.mark.altcoin,
pytest.mark.decred,
pytest.mark.skip_tr,
pytest.mark.skip_t3t1,
]
def test_send_decred(client: Client):
@ -72,13 +78,12 @@ def test_send_decred(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.FeeOverThreshold),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -194,14 +199,13 @@ def test_spend_from_stake_generation_and_revocation_decred(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_f8e2f2),
@ -276,7 +280,6 @@ def test_send_decred_change(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
@ -284,7 +287,7 @@ def test_send_decred_change(client: Client):
request_input(2),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -383,7 +386,6 @@ def test_decred_multisig_change(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
@ -391,7 +393,7 @@ def test_decred_multisig_change(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_9ac7d2),

@ -52,6 +52,7 @@ VECTORS = ( # path, script_type, address
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
@pytest.mark.parametrize("path, script_type, address", VECTORS)
def test_show_t1(
client: Client, path: str, script_type: messages.InputScriptType, address: str

@ -20,6 +20,7 @@ from trezorlib import btc, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
request_extra_data,
@ -61,13 +62,12 @@ def test_one_one_fee_sapling(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -126,16 +126,15 @@ def test_one_one_rewards_claim(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
messages.ButtonRequest(code=B.SignTx),
request_input(0),

@ -21,7 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import MNEMONIC12
from ...common import MNEMONIC12, is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -83,12 +83,11 @@ def test_2_of_3(client: Client, chunkify: bool):
)
# Expected responses are the same for both two signings
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_6b07c1),

@ -21,7 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import H_, parse_path
from ... import bip32
from ...common import MNEMONIC12
from ...common import MNEMONIC12, is_core
from ...tx_cache import TxCache
from .signtx import request_finished, request_input, request_meta, request_output
@ -145,7 +145,6 @@ def _responses(
change: int = 0,
foreign: bool = False,
):
is_core = client.features.model in ("T", "Safe 3")
resp = [
request_input(0),
request_input(1),
@ -154,7 +153,7 @@ def _responses(
if change != 1:
resp.append(messages.ButtonRequest(code=B.ConfirmOutput))
if is_core:
if is_core(client):
resp.append(messages.ButtonRequest(code=B.ConfirmOutput))
elif foreign:
resp.append(messages.ButtonRequest(code=B.UnknownDerivationPath))
@ -163,7 +162,7 @@ def _responses(
if change != 2:
resp.append(messages.ButtonRequest(code=B.ConfirmOutput))
if is_core:
if is_core(client):
resp.append(messages.ButtonRequest(code=B.ConfirmOutput))
elif foreign:
resp.append(messages.ButtonRequest(code=B.UnknownDerivationPath))

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -63,13 +64,12 @@ def test_opreturn(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
messages.ButtonRequest(code=B.SignTx),

@ -363,7 +363,7 @@ def test_signmessage_pagination(client: Client, message: str):
# We cannot differentiate between a newline and space in the message read from Trezor.
# TODO: do the check also for model R
if client.features.model == "T":
if client.model in (models.T2T1, models.T3T1):
message_read = IF.message_read.replace(" ", "").replace("...", "")
signed_message = message.replace("\n", "").replace(" ", "")
assert signed_message in message_read

@ -23,6 +23,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import Cancelled, TrezorFailure
from trezorlib.tools import H_, parse_path
from ...common import is_core
from ...input_flows import (
InputFlowLockTimeBlockHeight,
InputFlowLockTimeDatetime,
@ -127,13 +128,12 @@ def test_one_one_fee(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_0dac36),
@ -181,13 +181,12 @@ def test_testnet_one_two_fee(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -232,13 +231,12 @@ def test_testnet_fee_high_warning(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.FeeOverThreshold),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -285,14 +283,13 @@ def test_one_two_fee(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_50f6f1),
@ -348,16 +345,15 @@ def test_one_three_fee(client: Client, chunkify: bool):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(2),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -420,7 +416,6 @@ def test_two_two(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
@ -428,7 +423,7 @@ def test_two_two(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_ac4ca0),
@ -565,13 +560,12 @@ def test_lots_of_change(client: Client):
request_change_outputs = [request_output(i + 1) for i in range(cnt)]
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
]
+ request_change_outputs
+ [
@ -617,13 +611,12 @@ def test_fee_high_warning(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.FeeOverThreshold),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -706,13 +699,12 @@ def test_not_enough_funds(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.Failure(code=messages.FailureType.NotEnoughFunds),
]
)
@ -737,13 +729,12 @@ def test_p2sh(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_58d56a),
@ -825,7 +816,6 @@ def test_attack_change_outputs(client: Client):
# Test if the transaction can be signed normally
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
@ -833,7 +823,7 @@ def test_attack_change_outputs(client: Client):
request_output(0),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_ac4ca0),
@ -993,14 +983,13 @@ def test_attack_change_input_address(client: Client):
# Now run the attack, must trigger the exception
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_filter(messages.TxAck, attack_processor)
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -1045,13 +1034,12 @@ def test_spend_coinbase(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(FAKE_TXHASH_005f6f),
@ -1104,13 +1092,12 @@ def test_two_changes(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
request_output(2),
messages.ButtonRequest(code=B.SignTx),
@ -1164,13 +1151,12 @@ def test_change_on_main_chain_allowed(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -1429,13 +1415,12 @@ def test_lock_time(client: Client, lock_time: int, sequence: int):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
messages.ButtonRequest(code=B.SignTx),
request_input(0),

@ -22,6 +22,7 @@ from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import SafetyCheckLevel
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -216,20 +217,19 @@ def test_p2wpkh_in_p2sh_presigned(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(2),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_20912f),
@ -268,20 +268,19 @@ def test_p2wpkh_in_p2sh_presigned(client: Client):
# Test corrupted script hash in scriptsig.
inp1.script_sig[10] ^= 1
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(2),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_20912f),
@ -401,14 +400,13 @@ def test_p2wsh_external_presigned(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_ec16dc),
@ -447,14 +445,13 @@ def test_p2wsh_external_presigned(client: Client):
# Test corrupted signature in witness.
inp2.witness[10] ^= 1
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_ec16dc),
@ -513,14 +510,13 @@ def test_p2tr_external_presigned(client: Client):
script_type=messages.OutputScriptType.PAYTOTAPROOT,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(1),
@ -546,14 +542,13 @@ def test_p2tr_external_presigned(client: Client):
# Test corrupted signature in witness.
inp2.witness[10] ^= 1
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(1),
@ -617,17 +612,16 @@ def test_p2wpkh_with_proof(client: Client):
with client:
is_t1 = client.features.model == "1"
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_e5b7e2),
@ -711,14 +705,13 @@ def test_p2tr_with_proof(client: Client):
with client:
is_t1 = client.features.model == "1"
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_input(1),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
request_finished,
@ -115,8 +116,6 @@ def test_p2pkh_fee_bump(client: Client):
orig_index=1,
)
is_core = client.features.model in ("T", "Safe 3")
with client:
client.set_expected_responses(
[
@ -133,7 +132,7 @@ def test_p2pkh_fee_bump(client: Client):
request_meta(TXHASH_beafc7),
request_input(0, TXHASH_beafc7),
request_output(0, TXHASH_beafc7),
(is_core, request_orig_input(0, TXHASH_50f6f1)),
(is_core(client), request_orig_input(0, TXHASH_50f6f1)),
request_orig_input(0, TXHASH_50f6f1),
request_orig_output(0, TXHASH_50f6f1),
request_orig_output(1, TXHASH_50f6f1),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -66,16 +67,15 @@ def test_send_p2sh(client: Client, chunkify: bool):
amount=123_456_789 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_20912f),
@ -125,13 +125,12 @@ def test_send_p2sh_change(client: Client):
amount=123_456_789 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -181,13 +180,12 @@ def test_testnet_segwit_big_amount(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(prev_hash),
@ -239,12 +237,11 @@ def test_send_multisig_1(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_338e2d),
@ -307,17 +304,16 @@ def test_attack_change_input_address(client: Client):
# Test if the transaction can be signed normally.
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
# The user is required to confirm transfer to another account.
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_20912f),
@ -387,17 +383,19 @@ def test_attack_mixed_inputs(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput),
(
is_core,
is_core(client),
messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput),
),
(is_core, messages.ButtonRequest(code=messages.ButtonRequestType.SignTx)),
(
is_core(client),
messages.ButtonRequest(code=messages.ButtonRequestType.SignTx),
),
messages.ButtonRequest(code=messages.ButtonRequestType.FeeOverThreshold),
messages.ButtonRequest(code=messages.ButtonRequestType.SignTx),
request_input(0),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import H_, parse_path
from ...bip32 import deserialize
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -81,16 +82,15 @@ def test_send_p2sh(client: Client):
amount=123_456_789 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_20912f),
@ -137,13 +137,12 @@ def test_send_p2sh_change(client: Client):
amount=123_456_789 - 11_000 - 12_300_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -191,16 +190,15 @@ def test_send_native(client: Client):
amount=100_000 - 40_000 - 10_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_b36780),
@ -279,13 +277,12 @@ def test_send_native_change(client: Client):
amount=100_000 - 40_000 - 10_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -347,22 +344,20 @@ def test_send_both(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(2),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core, messages.ButtonRequest(code=B.SignTx)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.SignTx)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_65047a),
@ -433,12 +428,11 @@ def test_send_multisig_1(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_b9abfa),
@ -511,12 +505,11 @@ def test_send_multisig_2(client: Client):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_b9abfa),
@ -596,13 +589,12 @@ def test_send_multisig_3_change(client: Client):
script_type=messages.OutputScriptType.PAYTOP2SHWITNESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.UnknownDerivationPath),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_b9abfa),
@ -683,13 +675,12 @@ def test_send_multisig_4_change(client: Client):
script_type=messages.OutputScriptType.PAYTOWITNESS,
)
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.UnknownDerivationPath),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_b9abfa),
@ -785,18 +776,17 @@ def test_multisig_mismatch_inputs_single(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
# Ensure that the multisig output is not identified as a change output.
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_1c022d),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import H_, parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
assert_tx_matches,
@ -79,13 +80,12 @@ def test_send_p2tr(client: Client, chunkify: bool):
script_type=messages.OutputScriptType.PAYTOADDRESS,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
@ -134,14 +134,13 @@ def test_send_two_with_change(client: Client):
amount=6_800 + 13_000 - 200 - 15_000,
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -224,8 +223,6 @@ def test_send_mixed(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
# process inputs
@ -236,19 +233,19 @@ def test_send_mixed(client: Client):
# approve outputs
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(2),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(3),
messages.ButtonRequest(code=B.ConfirmOutput),
request_output(4),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core, messages.ButtonRequest(code=B.SignTx)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.SignTx)),
messages.ButtonRequest(code=B.SignTx),
# verify inputs
request_input(0),
@ -358,8 +355,6 @@ def test_attack_script_type(client: Client):
return msg
with client:
is_core = client.features.model in ("T", "Safe 3")
is_core = client.features.model in ("T", "Safe 3")
client.set_filter(messages.TxAck, attack_processor)
client.set_expected_responses(
[
@ -367,8 +362,8 @@ def test_attack_script_type(client: Client):
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core, messages.ButtonRequest(code=B.SignTx)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.SignTx)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_input(1),

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import is_core
from ...tx_cache import TxCache
from .signtx import (
request_extra_data,
@ -106,13 +107,12 @@ def test_one_one_fee_sapling(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_e38206),
@ -260,14 +260,13 @@ def test_external_presigned(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_e38206),

@ -16,7 +16,7 @@
import pytest
from trezorlib import cardano, device, messages
from trezorlib import cardano, device, messages, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
@ -33,11 +33,13 @@ def show_details_input_flow(client: Client):
yield
client.debug.wait_layout()
# Clicking for model T, pressing right for model R
if client.features.model == "T":
if client.model in (models.T2T1, models.T3T1):
SHOW_ALL_BUTTON_POSITION = (143, 167)
client.debug.click(SHOW_ALL_BUTTON_POSITION)
elif client.features.model == "Safe 3":
elif client.model is models.T2B1:
client.debug.press_yes()
else:
raise NotImplementedError
# reset ui flow to continue "automatically"
client.ui.input_flow = None
yield

@ -28,6 +28,7 @@ from ...input_flows import InputFlowShowXpubQRCode
@pytest.mark.eos
@pytest.mark.skip_t1
@pytest.mark.skip_tr # coin not supported
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
def test_eos_get_public_key(client: Client):
with client:

@ -31,6 +31,7 @@ pytestmark = [
pytest.mark.eos,
pytest.mark.skip_t1,
pytest.mark.skip_tr, # coin not supported
pytest.mark.skip_t3t1,
pytest.mark.setup_client(mnemonic=MNEMONIC12),
]

@ -199,7 +199,8 @@ METHODS = (
_call_signmessage,
pytest.param(_call_sign_typed_data, marks=pytest.mark.skip_t1),
pytest.param(
_call_sign_typed_data_hash, marks=[pytest.mark.skip_t2, pytest.mark.skip_tr]
_call_sign_typed_data_hash,
marks=[pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1],
),
)

@ -46,6 +46,7 @@ def test_slip25_disallowed(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_legacy_restrictions(client: Client):
path = parse_path("m/46'")
with pytest.raises(TrezorFailure, match="Invalid path for EthereumGetPublicKey"):

@ -43,6 +43,7 @@ def test_ethereum_sign_typed_data(client: Client, parameters, result):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
@parametrize_using_common_fixtures("ethereum/sign_typed_data.json")
def test_ethereum_sign_typed_data_blind(client: Client, parameters, result):
with client:

@ -16,7 +16,7 @@
import pytest
from trezorlib import ethereum, exceptions, messages
from trezorlib import ethereum, exceptions, messages, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.debuglink import message_filters
from trezorlib.exceptions import TrezorFailure
@ -208,7 +208,7 @@ def test_data_streaming(client: Client):
checked in vectorized function above.
"""
with client:
is_t1 = client.features.model == "1"
is_t1 = client.model is models.T1B1
client.set_expected_responses(
[
messages.ButtonRequest(code=messages.ButtonRequestType.SignTx),

@ -26,6 +26,7 @@ from ...common import MNEMONIC12
@pytest.mark.altcoin
@pytest.mark.nem
@pytest.mark.skip_tr # coin not supported,
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
@pytest.mark.parametrize("chunkify", (True, False))
def test_nem_getaddress(client: Client, chunkify: bool):

@ -28,6 +28,7 @@ pytestmark = [
pytest.mark.altcoin,
pytest.mark.nem,
pytest.mark.skip_tr, # coin not supported,
pytest.mark.skip_t3t1,
pytest.mark.setup_client(mnemonic=MNEMONIC12),
]

@ -26,6 +26,7 @@ pytestmark = [
pytest.mark.altcoin,
pytest.mark.nem,
pytest.mark.skip_tr, # coin not supported,
pytest.mark.skip_t3t1,
pytest.mark.setup_client(mnemonic=MNEMONIC12),
]

@ -26,6 +26,7 @@ pytestmark = [
pytest.mark.altcoin,
pytest.mark.nem,
pytest.mark.skip_tr, # coin not supported,
pytest.mark.skip_t3t1,
pytest.mark.setup_client(mnemonic=MNEMONIC12),
]

@ -20,12 +20,13 @@ from trezorlib import messages, nem
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path
from ...common import MNEMONIC12
from ...common import MNEMONIC12, is_core
pytestmark = [
pytest.mark.altcoin,
pytest.mark.nem,
pytest.mark.skip_tr, # coin not supported,
pytest.mark.skip_t3t1,
pytest.mark.setup_client(mnemonic=MNEMONIC12),
]
@ -33,7 +34,6 @@ pytestmark = [
# assertion data from T1
@pytest.mark.parametrize("chunkify", (True, False))
def test_nem_signtx_simple(client: Client, chunkify: bool):
is_core = client.features.model in ("T", "Safe 3")
with client:
client.set_expected_responses(
[
@ -42,7 +42,7 @@ def test_nem_signtx_simple(client: Client, chunkify: bool):
# Unencrypted message
messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput),
(
is_core,
is_core(client),
messages.ButtonRequest(
code=messages.ButtonRequestType.ConfirmOutput
),
@ -85,7 +85,6 @@ def test_nem_signtx_simple(client: Client, chunkify: bool):
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
def test_nem_signtx_encrypted_payload(client: Client):
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
# Confirm transfer and network fee
@ -93,7 +92,7 @@ def test_nem_signtx_encrypted_payload(client: Client):
# Ask for encryption
messages.ButtonRequest(code=messages.ButtonRequestType.ConfirmOutput),
(
is_core,
is_core(client),
messages.ButtonRequest(
code=messages.ButtonRequestType.ConfirmOutput
),

@ -82,6 +82,7 @@ def test_seed_mismatch(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_invalid_seed_t1(client: Client):
with pytest.raises(exceptions.TrezorFailure, match="Invalid seed"):
do_recover(client, ["stick"] * 12)

@ -25,7 +25,7 @@ from ...common import MNEMONIC12
PIN4 = "1234"
PIN6 = "789456"
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr]
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1]
@pytest.mark.setup_client(uninitialized=True)

@ -22,7 +22,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from ...common import EXTERNAL_ENTROPY, generate_entropy
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr]
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1]
STRENGTH = 128

@ -23,7 +23,7 @@ from trezorlib.tools import parse_path
from ...common import EXTERNAL_ENTROPY, generate_entropy
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr]
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1]
def reset_device(client: Client, strength: int):

@ -16,6 +16,7 @@ ROOT_PUBLIC_KEY = bytes.fromhex(
)
@pytest.mark.skip_t3t1 # FIXME https://github.com/trezor/trezor-firmware/issues/3596
@pytest.mark.parametrize(
"challenge",
(

@ -26,6 +26,7 @@ from trezorlib.tools import H_
pytestmark = [
pytest.mark.skip_t2,
pytest.mark.skip_tr,
pytest.mark.skip_t3t1,
pytest.mark.flaky(max_runs=5),
]

@ -27,7 +27,7 @@ PIN = "1234"
def _assert_busy(client: Client, should_be_busy: bool, screen: str = "Homescreen"):
assert client.features.busy is should_be_busy
if client.debug.model in ("T", "Safe 3"):
if client.model in (models.T2T1, models.T2B1, models.T3T1):
if should_be_busy:
assert "CoinJoinProgress" in client.debug.read_layout().all_components()
else:

@ -26,6 +26,7 @@ from ..common import MNEMONIC12
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_layout(client: Client):
layout = client.debug.state().layout
assert len(layout) == 1024
@ -33,6 +34,7 @@ def test_layout(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
def test_mnemonic(client: Client):
client.ensure_unlocked()
@ -42,6 +44,7 @@ def test_mnemonic(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(mnemonic=MNEMONIC12, pin="1234", passphrase="")
def test_pin(client: Client):
resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))

@ -2,13 +2,15 @@ from hashlib import blake2s
import pytest
from trezorlib import firmware
from trezorlib import firmware, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
# size of FIRMWARE_AREA, see core/embed/models/model_*_layout.c
FIRMWARE_LENGTHS = {
"1": 7 * 128 * 1024 + 64 * 1024,
"T": 13 * 128 * 1024,
"Safe 3": 13 * 128 * 1024,
models.T1B1: 7 * 128 * 1024 + 64 * 1024,
models.T2T1: 13 * 128 * 1024,
models.T2B1: 13 * 128 * 1024,
models.T3T1: 208 * 8 * 1024,
}
@ -16,7 +18,7 @@ def test_firmware_hash_emu(client: Client) -> None:
if client.features.fw_vendor != "EMULATOR":
pytest.skip("Only for emulator")
data = b"\xff" * FIRMWARE_LENGTHS[client.features.model]
data = b"\xff" * FIRMWARE_LENGTHS[client.model]
expected_hash = blake2s(data).digest()
hash = firmware.get_hash(client, None)
@ -34,7 +36,7 @@ def test_firmware_hash_hw(client: Client) -> None:
# TODO get firmware image from outside the environment, check for actual result
challenge = b"Hello Trezor"
empty_data = b"\xff" * FIRMWARE_LENGTHS[client.features.model]
empty_data = b"\xff" * FIRMWARE_LENGTHS[client.model]
empty_hash = blake2s(empty_data).digest()
empty_hash_challenge = blake2s(empty_data, key=challenge).digest()

@ -27,7 +27,11 @@ from ..translations import LANGUAGES, build_and_sign_blob, get_lang_json, set_la
pytestmark = pytest.mark.skip_t1
MAX_DATA_LENGTH = {models.T2T1: 48 * 1024, models.T2B1: 32 * 1024}
MAX_DATA_LENGTH = {
models.T2T1: 48 * 1024,
models.T2B1: 32 * 1024,
models.T3T1: 256 * 1024,
}
def get_ping_button(lang: str) -> str:
@ -59,7 +63,7 @@ def _check_ping_screen_texts(client: Client, title: str, right_button: str) -> N
client.debug.press_yes()
# TT does not have a right button text (but a green OK tick)
if client.features.model == "T":
if client.model in (models.T2T1, models.T3T1):
right_button = "-"
with client:

@ -135,6 +135,7 @@ def test_apply_settings_passphrase_on_device(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
def test_apply_homescreen_tr_toif_good(client: Client):
with client:
_set_expected_responses(client)
@ -147,6 +148,7 @@ def test_apply_homescreen_tr_toif_good(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(pin=None) # so that "PIN NOT SET" is shown in the header
def test_apply_homescreen_tr_toif_with_notification(client: Client):
with client:
@ -156,6 +158,7 @@ def test_apply_homescreen_tr_toif_with_notification(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
def test_apply_homescreen_tr_toif_with_long_label(client: Client):
with client:
_set_expected_responses(client)
@ -172,6 +175,7 @@ def test_apply_homescreen_tr_toif_with_long_label(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
def test_apply_homescreen_tr_toif_wrong_size(client: Client):
# 64x64 img
img = b"TOIG@\x00@\x009\x02\x00\x00}R\xdb\x81$A\x08\"\x03\xf3\xcf\xd2\x0c<\x01-{\xefc\xe6\xd5\xbbU\xa2\x08T\xd6\xcfw\xf4\xe7\xc7\xb7X\xf1\xe3\x1bl\xf0\xf7\x1b\xf8\x1f\xcf\xe7}\xe1\x83\xcf|>\x8d%\x14\xa5\xb3\xe9p5\xa1;~4:\xcd\xe0&\x11\x1d\xe9\xf6\xa1\x1fw\xf54\x95eWx\xda\xd0u\x91\x86\xb8\xbc\xdf\xdc\x008f\x15\xc6\xf6\x7f\xf0T\xb8\xc1\xa3\xc5_A\xc0G\x930\xe7\xdc=\xd5\xa7\xc1\xbcI\x16\xb8s\x9c&\xaa\x06\xc1}\x8b\x19\x9d'c\xc3\xe3^\xc3m\xb6n\xb0(\x16\xf6\xdeg\xb3\x96:i\xe5\x9c\x02\x93\x9fF\x9f-\xa7\"w\xf3X\x9f\x87\x08\x84\"v,\xab!9:<j+\xcb\xf3_\xc7\xd6^<\xce\xc1\xb8!\xec\x8f/\xb1\xc1\x8f\xbd\xcc\x06\x90\x0e\x98)[\xdb\x15\x99\xaf\xf2~\x8e\xd0\xdb\xcd\xfd\x90\x12\xb6\xdd\xc3\xdd|\x96$\x01P\x86H\xbc\xc0}\xa2\x08\xe5\x82\x06\xd2\xeb\x07[\r\xe4\xdeP\xf4\x86;\xa5\x14c\x12\xe3\xb16x\xad\xc7\x1d\x02\xef\x86<\xc6\x95\xd3/\xc4 \xa1\xf5V\xe2\t\xb2\x8a\xd6`\xf2\xcf\xb7\xd6\x07\xdf8X\xa7\x18\x03\x96\x82\xa4 \xeb.*kP\xceu\x9d~}H\xe9\xb8\x04<4\xff\xf8\xcf\xf6\xa0\xf2\xfcM\xe3/?k\xff\x18\x1d\xb1\xee\xc5\xf5\x1f\x01\x14\x03;\x1bU\x1f~\xcf\xb3\xf7w\xe5\nMfd/\xb93\x9fq\x9bQ\xb7'\xbfvq\x1d\xce\r\xbaDo\x90\xbc\xc5:?;\x84y\x8a\x1e\xad\xe9\xb7\x14\x10~\x9b@\xf8\x82\xdc\x89\xe7\xf0\xe0k4o\x9a\xa0\xc4\xb9\xba\xc56\x01i\x85EO'e6\xb7\x15\xb4G\x05\xe1\xe7%\xd3&\x93\x91\xc9CTQ\xeb\xcc\xd0\xd7E9\xa9JK\xcc\x00\x95(\xdc.\xd2#7:Yo}y_*\x1a\xae6)\x97\x9d\xc0\x80vl\x02\\M\xfe\xc9sW\xa8\xfbD\x99\xb8\xb0:\xbc\x80\xfd\xef\xd3\x94\xbe\x18j9z\x12S\xa1\xec$\x1c\xe3\xd1\xd0\xf4\xdd\xbfI\xf1rBj\x0f\x1cz\x1d\xf7\xa5tR\xb3\xfc\xa4\xd0\xfah\xc3Mj\xbe\x14r\x9d\x84z\xd2\x7f\x13\xb4w\xce\xa0\xaeW\xa4\x18\x0b\xe4\x8f\xe6\xc3\xbeQ\x93\xb0L<J\xe3g9\xb5W#f\xd1\x0b\x96|\xd6z1;\x85\x7f\xe3\xe6[\x02A\xdc\xa4\x02\x1b\x91\x88\x7f"
@ -182,6 +186,7 @@ def test_apply_homescreen_tr_toif_wrong_size(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
def test_apply_homescreen_tr_upload_jpeg_fail(client: Client):
with open(HERE / "test_bg.jpg", "rb") as f:
img = f.read()
@ -192,6 +197,7 @@ def test_apply_homescreen_tr_upload_jpeg_fail(client: Client):
@pytest.mark.skip_t1
@pytest.mark.skip_t2
@pytest.mark.skip_t3t1
def test_apply_homescreen_tr_upload_t1_fail(client: Client):
with pytest.raises(exceptions.TrezorFailure), client:
_set_expected_responses(client)
@ -327,6 +333,7 @@ def test_apply_homescreen_jpeg_wrong_size(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_apply_homescreen(client: Client):
with client:
_set_expected_responses(client)

@ -29,7 +29,7 @@ WIPE_CODE6 = "456789"
WIPE_CODE_MAX = "".join(chr((i % 9) + ord("1")) for i in range(MAX_PIN_LENGTH))
WIPE_CODE_TOO_LONG = WIPE_CODE_MAX + "1"
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr]
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1]
def _set_wipe_code(client: Client, pin, wipe_code):

@ -16,7 +16,7 @@
import pytest
from trezorlib import btc, device, messages
from trezorlib import btc, device, messages, models
from trezorlib.client import MAX_PIN_LENGTH, PASSPHRASE_TEST_PATH
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
@ -38,9 +38,13 @@ def _check_wipe_code(client: Client, pin: str, wipe_code: str):
# Try to change the PIN to the current wipe code value. The operation should fail.
with client, pytest.raises(TrezorFailure):
client.use_pin_sequence([pin, wipe_code, wipe_code])
br_amount = 5 if client.debug.model == "T" else 6
br_count = {
models.T2T1: 5,
models.T2B1: 6,
models.T3T1: 5,
}[client.model]
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
[messages.ButtonRequest()] * br_count
+ [messages.Failure(code=messages.FailureType.PinInvalid)]
)
device.change_pin(client)
@ -62,10 +66,15 @@ def test_set_remove_wipe_code(client: Client):
_ensure_unlocked(client, PIN4)
assert client.features.wipe_code_protection is False
br_count = {
models.T2T1: 5,
models.T2B1: 6,
models.T3T1: 5,
}[client.model]
with client:
br_amount = 5 if client.debug.model == "T" else 6
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
[messages.ButtonRequest()] * br_count
+ [messages.Success, messages.Features]
)
client.use_pin_sequence([PIN4, WIPE_CODE_MAX, WIPE_CODE_MAX])
@ -77,9 +86,8 @@ def test_set_remove_wipe_code(client: Client):
# Test change wipe code.
with client:
br_amount = 5 if client.debug.model == "T" else 6
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
[messages.ButtonRequest()] * br_count
+ [messages.Success, messages.Features]
)
client.use_pin_sequence([PIN4, WIPE_CODE6, WIPE_CODE6])
@ -118,10 +126,14 @@ def test_set_wipe_code_to_pin(client: Client):
_ensure_unlocked(client, PIN4)
with client:
br_amount = 7 if client.debug.model == "T" else 8
br_count = {
models.T2T1: 7,
models.T2B1: 8,
models.T3T1: 7,
}[client.model]
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
+ [messages.Success, messages.Features]
[messages.ButtonRequest()] * br_count
+ [messages.Success, messages.Features],
)
client.use_pin_sequence([PIN4, PIN4, WIPE_CODE4, WIPE_CODE4])
device.change_wipe_code(client)
@ -134,9 +146,13 @@ def test_set_wipe_code_to_pin(client: Client):
def test_set_pin_to_wipe_code(client: Client):
# Set wipe code.
with client:
br_amount = 4 if client.debug.model == "T" else 5
br_count = {
models.T2T1: 4,
models.T2B1: 5,
models.T3T1: 4,
}[client.model]
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
[messages.ButtonRequest()] * br_count
+ [messages.Success, messages.Features]
)
client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4])
@ -144,9 +160,13 @@ def test_set_pin_to_wipe_code(client: Client):
# Try to set the PIN to the current wipe code value.
with client, pytest.raises(TrezorFailure):
br_amount = 4 if client.debug.model == "T" else 6
br_count = {
models.T2T1: 4,
models.T2B1: 6,
models.T3T1: 4,
}[client.model]
client.set_expected_responses(
[messages.ButtonRequest()] * br_amount
[messages.ButtonRequest()] * br_count
+ [messages.Failure(code=messages.FailureType.PinInvalid)]
)
client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4])

@ -28,7 +28,7 @@ PIN6 = "789456"
PIN_MAX = "".join(chr((i % 9) + ord("1")) for i in range(MAX_PIN_LENGTH))
PIN_TOO_LONG = PIN_MAX + "1"
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr]
pytestmark = [pytest.mark.skip_t2, pytest.mark.skip_tr, pytest.mark.skip_t3t1]
def _check_pin(client: Client, pin):

@ -16,7 +16,7 @@
import pytest
from trezorlib import btc, device, messages
from trezorlib import btc, device, messages, models
from trezorlib.client import MAX_PIN_LENGTH, PASSPHRASE_TEST_PATH
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import Cancelled, TrezorFailure
@ -62,10 +62,14 @@ def test_set_pin(client: Client):
# Let's set new PIN
with client:
br_amount = 4 if client.debug.model == "T" else 6
br_count = {
models.T2T1: 4,
models.T2B1: 6,
models.T3T1: 4,
}[client.model]
client.use_pin_sequence([PIN_MAX, PIN_MAX])
client.set_expected_responses(
[messages.ButtonRequest] * br_amount + [messages.Success, messages.Features]
[messages.ButtonRequest] * br_count + [messages.Success, messages.Features]
)
device.change_pin(client)
@ -84,9 +88,13 @@ def test_change_pin(client: Client):
# Let's change PIN
with client:
client.use_pin_sequence([PIN4, PIN_MAX, PIN_MAX])
br_amount = 5 if client.debug.model == "T" else 6
br_count = {
models.T2T1: 5,
models.T2B1: 6,
models.T3T1: 5,
}[client.model]
client.set_expected_responses(
[messages.ButtonRequest] * br_amount + [messages.Success, messages.Features]
[messages.ButtonRequest] * br_count + [messages.Success, messages.Features]
)
device.change_pin(client)

@ -59,6 +59,7 @@ def test_correct_pin(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_incorrect_pin_t1(client: Client):
with pytest.raises(PinException):
client.use_pin_sequence([BAD_PIN])
@ -82,6 +83,7 @@ def test_incorrect_pin_t2(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_exponential_backoff_t1(client: Client):
for attempt in range(3):
start = time.time()

@ -21,7 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ..common import MNEMONIC12, WITH_MOCK_URANDOM, get_test_address
from ..common import MNEMONIC12, WITH_MOCK_URANDOM, get_test_address, is_core
from ..tx_cache import TxCache
from .bitcoin.signtx import (
request_finished,
@ -112,6 +112,7 @@ def test_apply_settings(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_change_pin_t1(client: Client):
_assert_protection(client)
with client:
@ -212,6 +213,7 @@ def test_wipe_device(client: Client):
@pytest.mark.setup_client(uninitialized=True)
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_reset_device(client: Client):
assert client.features.pin_protection is False
assert client.features.passphrase_protection is False
@ -241,6 +243,7 @@ def test_reset_device(client: Client):
@pytest.mark.setup_client(uninitialized=True)
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_recovery_device(client: Client):
assert client.features.pin_protection is False
assert client.features.passphrase_protection is False
@ -294,6 +297,7 @@ def test_sign_message(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
def test_verify_message_t1(client: Client):
_assert_protection(client)
with client:
@ -359,7 +363,6 @@ def test_signtx(client: Client):
_assert_protection(client)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.use_pin_sequence([PIN4])
client.set_expected_responses(
[
@ -368,7 +371,7 @@ def test_signtx(client: Client):
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_meta(TXHASH_50f6f1),

@ -113,7 +113,10 @@ def test_sd_protect_unlock(client: Client):
client.debug.input("1234")
yield # SD card problem
TR.assert_in(layout().text_content(), "sd_card__unplug_and_insert_correct")
TR.assert_in_multiple(
layout().text_content(),
["sd_card__unplug_and_insert_correct", "sd_card__insert_correct_card"],
)
client.debug.press_no() # close
with client, pytest.raises(TrezorFailure) as e:

@ -18,7 +18,7 @@ import random
import pytest
from trezorlib import device, exceptions, messages
from trezorlib import device, exceptions, messages, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import FailureType, SafetyCheckLevel
@ -316,6 +316,7 @@ def test_passphrase_always_on_device(client: Client):
@pytest.mark.skip_t2
@pytest.mark.skip_tr
@pytest.mark.skip_t3t1
@pytest.mark.setup_client(passphrase="")
def test_passphrase_on_device_not_possible_on_t1(client: Client):
# This setting makes no sense on T1.
@ -401,12 +402,14 @@ def test_hide_passphrase_from_host(client: Client):
client.debug.wait_layout().text_content(),
"passphrase__access_hidden_wallet",
)
if client.debug.model == "T":
if client.model in (models.T2T1, models.T3T1):
client.debug.press_yes()
elif client.debug.model == "Safe 3":
elif client.model is models.T2B1:
client.debug.press_right()
client.debug.press_right()
client.debug.press_yes()
else:
raise KeyError
client.watch_layout()
client.set_input_flow(input_flow)

@ -21,6 +21,7 @@ from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure
from trezorlib.tools import parse_path
from ...common import is_core
from ..bitcoin.signtx import request_finished, request_input, request_output
B = messages.ButtonRequestType
@ -95,13 +96,12 @@ def test_spend_v4_input(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
@ -144,13 +144,12 @@ def test_send_to_multisig(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
@ -192,13 +191,12 @@ def test_spend_v5_input(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),
@ -246,13 +244,12 @@ def test_one_two(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -305,13 +302,12 @@ def test_unified_address(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
request_output(1),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
@ -370,14 +366,13 @@ def test_external_presigned(client: Client):
)
with client:
is_core = client.features.model in ("T", "Safe 3")
client.set_expected_responses(
[
request_input(0),
request_input(1),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(1),
request_input(0),
@ -483,12 +478,11 @@ def test_spend_multisig(client: Client):
)
# Expected responses are the same for both two signings
is_core = client.features.model in ("T", "Safe 3")
expected_responses = [
request_input(0),
request_output(0),
messages.ButtonRequest(code=B.ConfirmOutput),
(is_core, messages.ButtonRequest(code=B.ConfirmOutput)),
(is_core(client), messages.ButtonRequest(code=B.ConfirmOutput)),
messages.ButtonRequest(code=B.SignTx),
request_input(0),
request_output(0),

@ -14,7 +14,7 @@ from __future__ import annotations
import time
from typing import Callable, Generator
from trezorlib import messages
from trezorlib import messages, models
from trezorlib.debuglink import DebugLink, LayoutContent
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.debuglink import multipage_content
@ -44,8 +44,8 @@ class InputFlowBase:
self.BAK = BackupFlow(self.client)
self.ETH = EthereumFlow(self.client)
def model(self) -> str | None:
return self.client.features.model
def model(self) -> str | models.TrezorModel:
return self.client.model
def get(self) -> Callable[[], BRGeneratorType]:
self.client.watch_layout(True)
@ -53,10 +53,12 @@ class InputFlowBase:
# There could be one common input flow for all models
if hasattr(self, "input_flow_common"):
return getattr(self, "input_flow_common")
elif self.model() == "T":
elif self.model() is models.T2T1:
return self.input_flow_tt
elif self.model() == "Safe 3":
elif self.model() is models.T2B1:
return self.input_flow_tr
elif self.model() is models.T3T1:
return self.input_flow_t3t1
else:
raise ValueError("Unknown model")
@ -68,6 +70,10 @@ class InputFlowBase:
"""Special for TR"""
raise NotImplementedError
def input_flow_t3t1(self) -> BRGeneratorType:
"""Special for T3T1"""
raise NotImplementedError
def text_content(self) -> str:
return self.debug.wait_layout().text_content()
@ -91,7 +97,7 @@ class InputFlowSetupDevicePINWIpeCode(InputFlowBase):
yield # do you want to set/change the wipe code?
self.debug.press_yes()
if self.debug.model == "Safe 3":
if self.model() is models.T2B1:
yield from swipe_if_necessary(self.debug) # wipe code info
self.debug.press_yes()
@ -120,7 +126,7 @@ class InputFlowNewCodeMismatch(InputFlowBase):
yield # do you want to set/change the pin/wipe code?
self.debug.press_yes()
if self.debug.model == "Safe 3":
if self.model() is models.T2B1:
yield from swipe_if_necessary(self.debug) # code info
self.debug.press_yes()
@ -247,6 +253,28 @@ class InputFlowSignMessagePagination(InputFlowBase):
yield
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
# collect screen contents into `message_read`.
# Using a helper debuglink function to assemble the final text.
layouts: list[LayoutContent] = []
br = yield # confirm address
self.debug.wait_layout()
self.debug.press_yes()
br = yield
assert br.pages is not None
for i in range(br.pages):
layout = self.debug.wait_layout()
layouts.append(layout)
if i < br.pages - 1:
self.debug.swipe_up()
self.message_read = multipage_content(layouts)
self.debug.press_yes()
class InputFlowSignMessageInfo(InputFlowBase):
def __init__(self, client: Client):
@ -269,6 +297,23 @@ class InputFlowSignMessageInfo(InputFlowBase):
self.debug.press_no(wait=True)
self.debug.press_yes(wait=True)
def input_flow_t3t1(self) -> BRGeneratorType:
yield
# show address/message info
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.press_no(wait=True)
self.debug.synchronize_at("IconDialog")
# address mismatch?
self.debug.press_no()
yield
self.debug.press_yes()
yield
self.debug.press_no()
yield
self.debug.press_no(wait=True)
self.debug.press_yes(wait=True)
class InputFlowShowAddressQRCode(InputFlowBase):
def __init__(self, client: Client):
@ -309,6 +354,20 @@ class InputFlowShowAddressQRCode(InputFlowBase):
self.debug.press_right()
self.debug.press_middle()
def input_flow_t3t1(self) -> BRGeneratorType:
yield
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.swipe_right(wait=True)
self.debug.swipe_left(wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.press_no(wait=True)
self.debug.press_no(wait=True)
self.debug.press_yes()
class InputFlowShowAddressQRCodeCancel(InputFlowBase):
def __init__(self, client: Client):
@ -340,6 +399,17 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase):
self.debug.press_right()
self.debug.press_right()
def input_flow_t3t1(self) -> BRGeneratorType:
yield
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.press_no(wait=True)
self.debug.press_yes()
class InputFlowShowMultisigXPUBs(InputFlowBase):
def __init__(self, client: Client, address: str, xpubs: list[str], index: int):
@ -422,6 +492,40 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
# show address
self.debug.press_middle()
def input_flow_t3t1(self) -> BRGeneratorType:
yield # multisig address warning
self.debug.press_yes()
yield # show address
layout = self.debug.wait_layout()
TR.assert_in(layout.title(), "address__title_receive_address")
assert "(MULTISIG)" in layout.title()
assert layout.text_content().replace(" ", "") == self.address
self.debug.click(buttons.CORNER_BUTTON)
assert "Qr" in self.all_components()
layout = self.debug.swipe_left(wait=True)
# address details
assert "Multisig 2 of 3" in layout.screen_content()
TR.assert_in(layout.screen_content(), "address_details__derivation_path")
# Three xpub pages with the same testing logic
for xpub_num in range(3):
expected_title = f"MULTISIG XPUB #{xpub_num + 1}"
layout = self.debug.swipe_left(wait=True)
assert expected_title in layout.title()
content = layout.text_content().replace(" ", "")
assert self.xpubs[xpub_num] in content
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# show address
self.debug.press_no(wait=True)
# address mismatch
self.debug.press_no(wait=True)
# show address
self.debug.press_yes()
class InputFlowShowXpubQRCode(InputFlowBase):
def __init__(self, client: Client, passphrase: bool = False):
@ -482,6 +586,33 @@ class InputFlowShowXpubQRCode(InputFlowBase):
# Confirm
self.debug.press_middle()
def input_flow_t3t1(self) -> BRGeneratorType:
if self.passphrase:
yield
self.debug.press_yes()
yield
self.debug.press_yes()
br = yield
layout = self.debug.wait_layout()
if "coinjoin" in layout.title().lower() or br.code == B.UnknownDerivationPath:
self.debug.press_yes()
br = yield
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.swipe_right(wait=True)
self.debug.swipe_left(wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.press_no(wait=True)
self.debug.press_no(wait=True)
for _ in range(br.pages - 1):
self.debug.swipe_up(wait=True)
self.debug.press_yes()
class InputFlowPaymentRequestDetails(InputFlowBase):
def __init__(self, client: Client, outputs: list[messages.TxOutputType]):
@ -512,6 +643,30 @@ class InputFlowPaymentRequestDetails(InputFlowBase):
yield # confirm transaction
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
yield # request to see details
self.debug.wait_layout()
self.debug.press_info()
yield # confirm first output
assert self.outputs[0].address[:16] in self.text_content() # type: ignore
self.debug.press_yes()
yield # confirm first output
self.debug.wait_layout()
self.debug.press_yes()
yield # confirm second output
assert self.outputs[1].address[:16] in self.text_content() # type: ignore
self.debug.press_yes()
yield # confirm second output
self.debug.wait_layout()
self.debug.press_yes()
yield # confirm transaction
self.debug.press_yes()
yield # confirm transaction
self.debug.press_yes()
class InputFlowSignTxHighFee(InputFlowBase):
def __init__(self, client: Client):
@ -607,6 +762,11 @@ class InputFlowSignTxInformation(InputFlowBase):
self.assert_content(content, "confirm_total__title_sending_from")
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
content = yield from sign_tx_go_to_info(self.client)
self.assert_content(content, "confirm_total__sending_from_account")
self.debug.press_yes()
class InputFlowSignTxInformationMixed(InputFlowBase):
def __init__(self, client: Client):
@ -636,6 +796,15 @@ class InputFlowSignTxInformationMixed(InputFlowBase):
self.assert_content(content, "confirm_total__title_sending_from")
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
# multiple accounts warning
yield
self.debug.press_yes()
content = yield from sign_tx_go_to_info(self.client)
self.assert_content(content, "confirm_total__sending_from_account")
self.debug.press_yes()
class InputFlowSignTxInformationCancel(InputFlowBase):
def __init__(self, client: Client):
@ -649,6 +818,10 @@ class InputFlowSignTxInformationCancel(InputFlowBase):
yield from sign_tx_go_to_info_tr(self.client)
self.debug.press_left()
def input_flow_t3t1(self) -> BRGeneratorType:
yield from sign_tx_go_to_info(self.client)
self.debug.press_no()
class InputFlowSignTxInformationReplacement(InputFlowBase):
def __init__(self, client: Client):
@ -685,6 +858,23 @@ class InputFlowSignTxInformationReplacement(InputFlowBase):
self.debug.press_right()
yield
def input_flow_t3t1(self) -> BRGeneratorType:
yield # confirm txid
self.debug.press_yes()
yield # confirm address
self.debug.press_yes()
# go back to address
self.debug.press_no()
# confirm address
self.debug.press_yes()
yield # confirm amount
self.debug.press_yes()
yield # transaction summary, press info
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
self.debug.press_yes()
def lock_time_input_flow_tt(
debug: DebugLink,
@ -746,6 +936,11 @@ class InputFlowLockTimeBlockHeight(InputFlowBase):
def input_flow_tr(self) -> BRGeneratorType:
yield from lock_time_input_flow_tr(self.debug, self.assert_func)
def input_flow_t3t1(self) -> BRGeneratorType:
yield from lock_time_input_flow_tt(
self.debug, self.assert_func, double_confirm=True
)
class InputFlowLockTimeDatetime(InputFlowBase):
def __init__(self, client: Client, lock_time_str: str):
@ -763,6 +958,9 @@ class InputFlowLockTimeDatetime(InputFlowBase):
def input_flow_tr(self) -> BRGeneratorType:
yield from lock_time_input_flow_tr(self.debug, self.assert_func)
def input_flow_t3t1(self) -> BRGeneratorType:
yield from lock_time_input_flow_tt(self.debug, self.assert_func)
class InputFlowEIP712ShowMore(InputFlowBase):
SHOW_MORE = (143, 167)
@ -773,9 +971,9 @@ class InputFlowEIP712ShowMore(InputFlowBase):
def _confirm_show_more(self) -> None:
"""Model-specific, either clicks a screen or presses a button."""
if self.model() == "T":
if self.model() in (models.T2T1, models.T3T1):
self.debug.click(self.SHOW_MORE)
elif self.model() == "Safe 3":
elif self.model() is models.T2B1:
self.debug.press_right()
def input_flow_common(self) -> BRGeneratorType:
@ -1087,6 +1285,31 @@ class InputFlowSlip39BasicBackup(InputFlowBase):
assert br.code == B.Success
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
yield # 1. Checklist
self.debug.press_yes()
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # 2. Number of shares (5)
self.debug.press_yes()
yield # 3. Checklist
self.debug.press_yes()
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # 4. Threshold (3)
self.debug.press_yes()
yield # 5. Checklist
self.debug.press_yes()
yield # 6. Confirm show seeds
self.debug.press_yes()
# Mnemonic phrases
self.mnemonics = yield from load_5_shares(self.debug)
br = yield # Confirm backup
assert br.code == B.Success
self.debug.press_yes()
class InputFlowSlip39BasicResetRecovery(InputFlowBase):
def __init__(self, client: Client):
@ -1140,6 +1363,24 @@ class InputFlowSlip39BasicResetRecovery(InputFlowBase):
assert br.code == B.Success
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
# 1. Confirm Reset
# 2. Backup your seed
# 3. Confirm warning
# 4. shares info
# 5. Set & Confirm number of shares
# 6. threshold info
# 7. Set & confirm threshold value
# 8. Confirm show seeds
yield from click_through(self.debug, screens=8, code=B.ResetDevice)
# Mnemonic phrases
self.mnemonics = yield from load_5_shares(self.debug)
br = yield # safety warning
assert br.code == B.Success
self.debug.press_yes()
def load_5_groups_5_shares(
debug: DebugLink,
@ -1229,6 +1470,40 @@ class InputFlowSlip39AdvancedBackup(InputFlowBase):
assert br.code == B.Success
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
yield # 1. Checklist
self.debug.press_yes()
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # 2. Set and confirm group count
self.debug.press_yes()
yield # 3. Checklist
self.debug.press_yes()
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # 4. Set and confirm group threshold
self.debug.press_yes()
yield # 5. Checklist
self.debug.press_yes()
for _ in range(5): # for each of 5 groups
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # Set & Confirm number of shares
self.debug.press_yes()
if self.click_info:
yield from click_info_button_tt(self.debug)
yield # Set & confirm share threshold value
self.debug.press_yes()
yield # Confirm show seeds
self.debug.press_yes()
# Mnemonic phrases - show & confirm shares for all groups
self.mnemonics = yield from load_5_groups_5_shares(self.debug)
br = yield # Confirm backup
assert br.code == B.Success
self.debug.press_yes()
class InputFlowSlip39AdvancedResetRecovery(InputFlowBase):
def __init__(self, client: Client, click_info: bool):
@ -1291,6 +1566,27 @@ class InputFlowSlip39AdvancedResetRecovery(InputFlowBase):
assert br.code == B.Success
self.debug.press_yes()
def input_flow_t3t1(self) -> BRGeneratorType:
# 1. Confirm Reset
# 2. Backup your seed
# 3. Confirm warning
# 4. shares info
# 5. Set & Confirm number of groups
# 6. threshold info
# 7. Set & confirm group threshold value
# 8-17: for each of 5 groups:
# 1. Set & Confirm number of shares
# 2. Set & confirm share threshold value
# 18. Confirm show seeds
yield from click_through(self.debug, screens=18, code=B.ResetDevice)
# Mnemonic phrases - show & confirm shares for all groups
self.mnemonics = yield from load_5_groups_5_shares(self.debug)
br = yield # safety warning
assert br.code == B.Success
self.debug.press_yes()
class InputFlowBip39RecoveryDryRun(InputFlowBase):
def __init__(self, client: Client, mnemonic: list[str], mismatch: bool = False):
@ -1377,7 +1673,7 @@ class InputFlowSlip39AdvancedRecoveryAbort(InputFlowBase):
def input_flow_common(self) -> BRGeneratorType:
yield from self.REC.confirm_recovery()
if self.debug.model == "T":
if self.model() in (models.T2T1, models.T3T1):
yield from self.REC.input_number_of_words(20)
yield from self.REC.abort_recovery(True)
@ -1390,7 +1686,7 @@ class InputFlowSlip39AdvancedRecoveryNoAbort(InputFlowBase):
def input_flow_common(self) -> BRGeneratorType:
yield from self.REC.confirm_recovery()
if self.debug.model == "T":
if self.model() in (models.T2T1, models.T3T1):
yield from self.REC.input_number_of_words(self.word_count)
yield from self.REC.abort_recovery(False)
else:
@ -1489,7 +1785,7 @@ class InputFlowSlip39BasicRecoveryAbort(InputFlowBase):
def input_flow_common(self) -> BRGeneratorType:
yield from self.REC.confirm_recovery()
if self.debug.model == "T":
if self.model() in (models.T2T1, models.T3T1):
yield from self.REC.input_number_of_words(20)
yield from self.REC.abort_recovery(True)
@ -1503,7 +1799,7 @@ class InputFlowSlip39BasicRecoveryNoAbort(InputFlowBase):
def input_flow_common(self) -> BRGeneratorType:
yield from self.REC.confirm_recovery()
if self.debug.model == "T":
if self.model() in (models.T2T1, models.T3T1):
yield from self.REC.input_number_of_words(self.word_count)
yield from self.REC.abort_recovery(False)
else:
@ -1605,11 +1901,11 @@ class InputFlowResetSkipBackup(InputFlowBase):
yield # Skip Backup
info_path = (
"backup__new_wallet_created"
if self.debug.model == "Safe 3"
if self.model() is models.T2B1
else "backup__new_wallet_successfully_created"
)
TR.assert_in(self.text_content(), info_path)
if self.debug.model == "Safe 3":
if self.model() is models.T2B1:
self.debug.press_right()
self.debug.press_no()
yield # Confirm skip backup

@ -1,4 +1,4 @@
from trezorlib import messages
from trezorlib import messages, models
from trezorlib.debuglink import TrezorClientDebugLink as Client
from . import translations as TR
@ -18,7 +18,7 @@ class PinFlow:
yield # Enter PIN
assert "PinKeyboard" in self.debug.wait_layout().all_components()
self.debug.input(pin)
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
yield # Reenter PIN
TR.assert_in(
self.debug.wait_layout().text_content(), "pin__reenter_to_confirm"
@ -40,7 +40,7 @@ class BackupFlow:
def confirm_new_wallet(self) -> BRGeneratorType:
yield
TR.assert_in(self.debug.wait_layout().text_content(), "reset__by_continuing")
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
self.debug.press_right()
self.debug.press_yes()
@ -56,7 +56,7 @@ class RecoveryFlow:
def confirm_recovery(self) -> BRGeneratorType:
yield
TR.assert_in(self._text_content(), "reset__by_continuing")
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
self.debug.press_right()
self.debug.press_yes()
@ -66,13 +66,13 @@ class RecoveryFlow:
self.debug.press_yes()
def setup_slip39_recovery(self, num_words: int) -> BRGeneratorType:
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
yield from self.tr_recovery_homescreen()
yield from self.input_number_of_words(num_words)
yield from self.enter_any_share()
def setup_bip39_recovery(self, num_words: int) -> BRGeneratorType:
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
yield from self.tr_recovery_homescreen()
yield from self.input_number_of_words(num_words)
yield from self.enter_your_backup()
@ -89,7 +89,7 @@ class RecoveryFlow:
title in self.debug.wait_layout().title().lower()
for title in TR.translate("recovery__title_dry_run", lower=True)
)
if self.debug.model == "Safe 3" and not is_dry_run:
if self.client.model is models.T2B1 and not is_dry_run:
# Normal recovery has extra info (not dry run)
self.debug.press_right(wait=True)
self.debug.press_right(wait=True)
@ -102,7 +102,7 @@ class RecoveryFlow:
title in self.debug.wait_layout().title().lower()
for title in TR.translate("recovery__title_dry_run", lower=True)
)
if self.debug.model == "Safe 3" and not is_dry_run:
if self.client.model is models.T2B1 and not is_dry_run:
# Normal recovery has extra info (not dry run)
self.debug.press_right(wait=True)
self.debug.press_right(wait=True)
@ -110,7 +110,7 @@ class RecoveryFlow:
def abort_recovery(self, confirm: bool) -> BRGeneratorType:
yield
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
TR.assert_in(self._text_content(), "recovery__num_of_words")
else:
TR.assert_in(self._text_content(), "recovery__enter_any_share")
@ -118,7 +118,7 @@ class RecoveryFlow:
yield
TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery")
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
self.debug.press_right()
if confirm:
self.debug.press_yes()
@ -128,7 +128,7 @@ class RecoveryFlow:
def input_number_of_words(self, num_words: int) -> BRGeneratorType:
br = yield
assert br.code == B.MnemonicWordCount
if self.debug.model == "Safe 3":
if self.client.model is models.T2B1:
TR.assert_in(self.debug.wait_layout().title(), "word_count__title")
else:
TR.assert_in(self._text_content(), "recovery__num_of_words")
@ -180,7 +180,7 @@ class RecoveryFlow:
assert br.code == B.Success
text = get_text_possible_pagination(self.debug, br)
# TODO: make sure the translations fit on one page
if self.client.debug.model != "T":
if self.client.model not in (models.T2T1, models.T3T1):
TR.assert_in(text, "recovery__dry_run_bip39_valid_match")
self.debug.press_yes()
@ -189,7 +189,7 @@ class RecoveryFlow:
assert br.code == B.Success
text = get_text_possible_pagination(self.debug, br)
# TODO: make sure the translations fit on one page
if self.client.debug.model != "T":
if self.client.model not in (models.T2T1, models.T3T1):
TR.assert_in(text, "recovery__dry_run_slip39_valid_match")
self.debug.press_yes()
@ -198,7 +198,7 @@ class RecoveryFlow:
assert br.code == B.Warning
text = get_text_possible_pagination(self.debug, br)
# TODO: make sure the translations fit on one page on TT
if self.client.debug.model != "T":
if self.client.model not in (models.T2T1, models.T3T1):
TR.assert_in(text, "recovery__dry_run_slip39_valid_mismatch")
self.debug.press_yes()
@ -207,7 +207,7 @@ class RecoveryFlow:
assert br.code == B.Warning
text = get_text_possible_pagination(self.debug, br)
# TODO: make sure the translations fit on one page
if self.client.debug.model != "T":
if self.client.model not in (models.T2T1, models.T3T1):
TR.assert_in(text, "recovery__dry_run_bip39_valid_mismatch")
self.debug.press_yes()
@ -240,7 +240,7 @@ class RecoveryFlow:
if index < len(shares) - 1:
if has_groups:
yield from self.success_share_group_entered()
if self.debug.model == "T" and click_info:
if self.client.model in (models.T2T1, models.T3T1) and click_info:
yield from self.tt_click_info()
yield from self.success_more_shares_needed()
@ -292,7 +292,7 @@ class EthereumFlow:
)
assert br.pages is not None
assert br.pages > 2
if self.debug.model == "T":
if self.client.model in (models.T2T1, models.T3T1):
self.debug.swipe_up(wait=True)
self.debug.swipe_up(wait=True)
self.debug.click(self.GO_BACK)
@ -312,7 +312,7 @@ class EthereumFlow:
yield
TR.assert_equals(self.debug.wait_layout().title(), "words__recipient")
if self.debug.model == "T":
if self.client.model in (models.T2T1, models.T3T1):
if cancel:
self.debug.press_no()
else:
@ -387,7 +387,7 @@ class EthereumFlow:
"ethereum__staking_claim_intro",
],
)
if self.debug.model == "T":
if self.client.model in (models.T2T1, models.T3T1):
# confirm intro
if info:
self.debug.press_info(wait=True)

@ -113,6 +113,18 @@ def assert_in(text: str, path: str, template: t.Iterable[t.Any] = ()) -> None:
assert False, f"{text} not found in {texts}"
def assert_in_multiple(
text: str, paths: list[str], template: t.Iterable[t.Any] = ()
) -> None:
texts: list[str] = []
for path in paths:
texts += _resolve_path_to_texts(path, template)
for tt in texts:
if tt in text.lower():
return
assert False, f"{text} not found in {texts}"
def assert_startswith(text: str, path: str, template: t.Iterable[t.Any] = ()) -> None:
texts = _resolve_path_to_texts(path, template)
for tt in texts:

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save