fix(core): set high BLE speed for translations upload
What changed, and why it matters
This commit is a small cleanup and bug fix for the T3W1 hardware wallet's Bluetooth translation upload. It makes sure the Bluetooth connection switches to a faster mode when uploading language translations, just like it already did when uploading custom homescreens. The change also wraps the speed-up logic in a reusable helper so it is harder to accidentally leave high-speed mode on. There is no direct security vulnerability here; it is a reliability/performance improvement.
No security action required. Treat as normal code-quality/performance patch. If desired, verify that `set_high_speed` failures do not leak state or suppress exceptions (the context manager returns False, so exceptions propagate correctly).
Security signals we found
No security-relevant signals in diff
Refactoring only: moves existing BLE speed toggle into reusable context manager
Adds missing high-speed BLE toggle for translation upload path
No input validation, authentication, or cryptographic changes
Evidence from the diff
The patch introduces a context manager (trezor.wire.high_speed) that enables BLE high-speed mode on entry and disables it on exit, even if an exception occurs. It refactors apply_settings.py to use this helper for homescreen uploads, and adds the same high-speed wrapping to change_language.py for translation uploads. The changelog explicitly frames this as improving translation upload speed over Bluetooth on the T3W1 device. No cryptographic, authorization, or input-validation changes are present.
Changed components
core/src/apps/management/apply_settings.pycore/src/apps/management/change_language.pycore/src/trezor/wire/__init__.pyTrezor Safe 3 / T3W1 Bluetooth translation upload flowInspect captured patch +35 / −15
diff --git a/core/.changelog.d/5995.fixed b/core/.changelog.d/5995.fixed
new file mode 100644
index 000000000..4e608feb4
--- /dev/null
+++ b/core/.changelog.d/5995.fixed
@@ -0,0 +1 @@
+[T3W1] Improve speed of translations upload over bluetooth.
diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py
index e22a27218..7072637ee 100644
--- a/core/src/apps/management/apply_settings.py
+++ b/core/src/apps/management/apply_settings.py
@@ -5,7 +5,7 @@ import trezorui_api
from trezor import TR, utils
from trezor.enums import ButtonRequestType, DisplayRotation
from trezor.ui.layouts import confirm_action
-from trezor.wire import DataError
+from trezor.wire import DataError, high_speed
if TYPE_CHECKING:
from buffer_types import AnyBytes
@@ -92,16 +92,8 @@ async def apply_settings(msg: ApplySettings) -> Success:
if homescreen_length is not None:
if homescreen is not None:
raise ProcessError("Mutually exclusive settings")
- if utils.USE_BLE:
- from trezorble import set_high_speed
-
- set_high_speed(True)
-
- try:
+ with high_speed:
homescreen = await _load_homescreen(homescreen_length)
- finally:
- if utils.USE_BLE:
- set_high_speed(False)
if homescreen is not None:
_validate_homescreen(homescreen)
diff --git a/core/src/apps/management/change_language.py b/core/src/apps/management/change_language.py
index 2e952f7b3..9d82dea24 100644
--- a/core/src/apps/management/change_language.py
+++ b/core/src/apps/management/change_language.py
@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING
from trezor import TR, translations
-from trezor.wire import DataError
+from trezor.wire import DataError, high_speed
if TYPE_CHECKING:
from typing import Callable
@@ -109,9 +109,11 @@ async def do_change_language(
# Requesting the data in chunks and storing them in the blob
data_to_fetch = data_length - len(header_data)
- await chunked.get_all_chunks(
- blob, data_to_fetch, offset=len(header_data), report=report
- )
+
+ with high_speed:
+ await chunked.get_all_chunks(
+ blob, data_to_fetch, offset=len(header_data), report=report
+ )
# When the data do not match the hash, do not write anything
try:
diff --git a/core/src/trezor/wire/__init__.py b/core/src/trezor/wire/__init__.py
index 391f6b3b8..286a72183 100644
--- a/core/src/trezor/wire/__init__.py
+++ b/core/src/trezor/wire/__init__.py
@@ -49,7 +49,8 @@ if __debug__:
if TYPE_CHECKING:
from buffer_types import AnyBytes
from trezorio import WireInterface
- from typing import Any, Callable, Coroutine, Generic, TypeVar
+ from types import TracebackType
+ from typing import Any, Callable, Coroutine, Generic, Optional, Type, TypeVar
from trezor.wire.thp.channel import Channel
@@ -64,6 +65,30 @@ else:
T = 0
+class _HighSpeed:
+ def __enter__(self) -> "_HighSpeed":
+ if utils.USE_BLE:
+ from trezorble import set_high_speed
+
+ set_high_speed(True)
+ return self
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[BaseException]],
+ exc: Optional[BaseException],
+ tb: Optional[TracebackType],
+ ) -> bool:
+ if utils.USE_BLE:
+ from trezorble import set_high_speed
+
+ set_high_speed(False)
+ return False
+
+
+high_speed: "_HighSpeed" = _HighSpeed()
+
+
class Provider(Generic[T]):
def __init__(self, obj: T) -> None:
self.obj = obj
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.