1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 14:28:07 +00:00

fix(core/monero): fix blinking progress indicators

[no changelog]
This commit is contained in:
Martin Milata 2022-10-30 18:01:06 +01:00
parent 95d8a21294
commit 75cee540a4
12 changed files with 124 additions and 132 deletions

View File

@ -13,6 +13,7 @@ if TYPE_CHECKING:
MoneroKeyImageSyncStepAck,
MoneroKeyImageSyncStepRequest,
)
from trezor.ui.layouts.common import ProgressLayout
from trezor.wire import Context
from apps.common.keychain import Keychain
@ -34,9 +35,10 @@ async def key_image_sync(
state = KeyImageSync()
res = await _init_step(state, ctx, msg, keychain)
progress = layout.monero_keyimage_sync_progress()
while state.current_output + 1 < state.num_outputs:
step = await ctx.call(res, MoneroKeyImageSyncStepRequest)
res = await _sync_step(state, ctx, step)
res = _sync_step(state, ctx, step, progress)
gc.collect()
await ctx.call(res, MoneroKeyImageSyncFinalRequest)
@ -92,8 +94,11 @@ async def _init_step(
return MoneroKeyImageExportInitAck()
async def _sync_step(
s: KeyImageSync, ctx: Context, tds: MoneroKeyImageSyncStepRequest
def _sync_step(
s: KeyImageSync,
ctx: Context,
tds: MoneroKeyImageSyncStepRequest,
progress: ProgressLayout,
) -> MoneroKeyImageSyncStepAck:
from trezor import log
from trezor.messages import (
@ -111,7 +116,8 @@ async def _sync_step(
buff = bytearray(32 * 3)
buff_mv = memoryview(buff)
await layout.keyimage_sync_step(ctx, s.current_output, s.num_outputs)
if s.current_output is not None and s.num_outputs > 0:
progress.report(1000 * (s.current_output + 1) // s.num_outputs)
for td in tds.tdis:
s.current_output += 1

View File

@ -1,9 +1,13 @@
from typing import TYPE_CHECKING
from trezor import ui
from trezor.enums import ButtonRequestType
from trezor.ui.layouts import confirm_action, confirm_metadata
from trezor.ui.popup import Popup
from trezor.ui.layouts import ( # noqa: F401
confirm_action,
confirm_metadata,
monero_keyimage_sync_progress,
monero_live_refresh_progress,
monero_transaction_progress_inner,
)
DUMMY_PAYMENT_ID = b"\x00\x00\x00\x00\x00\x00\x00\x00"
@ -22,6 +26,35 @@ if TYPE_CHECKING:
BRT_SignTx = ButtonRequestType.SignTx # global_import_cache
class MoneroTransactionProgress:
def __init__(self) -> None:
self.inner = None
def step(self, state: State, step: int, sub_step: int = 0) -> None:
if step == 0 or self.inner is None:
self.inner = monero_transaction_progress_inner()
info = "Signing..."
elif step == state.STEP_INP:
info = f"Processing inputs\n{sub_step + 1}/{state.input_count}"
elif step == state.STEP_VINI:
info = f"Hashing inputs\n{sub_step + 1}/{state.input_count}"
elif step == state.STEP_ALL_IN:
info = "Processing..."
elif step == state.STEP_OUT:
info = f"Processing outputs\n{sub_step + 1}/{state.output_count}"
elif step == state.STEP_ALL_OUT:
info = "Postprocessing..."
elif step == state.STEP_SIGN:
info = f"Signing inputs\n{sub_step + 1}/{state.input_count}"
else:
info = "Processing..."
state.progress_cur += 1
p = 1000 * state.progress_cur // state.progress_total
self.inner.report(p, info)
def _format_amount(value: int) -> str:
from trezor import strings
@ -78,6 +111,7 @@ async def require_confirm_transaction(
state: State,
tsx_data: MoneroTransactionData,
network_type: MoneroNetworkType,
progress: MoneroTransactionProgress,
) -> None:
"""
Ask for confirmation from user.
@ -112,7 +146,7 @@ async def require_confirm_transaction(
await _require_confirm_payment_id(ctx, payment_id)
await _require_confirm_fee(ctx, tsx_data.fee)
await transaction_step(state, 0)
progress.step(state, 0)
async def _require_confirm_output(
@ -173,87 +207,3 @@ async def _require_confirm_unlock_time(ctx: Context, unlock_time: int) -> None:
str(unlock_time),
BRT_SignTx,
)
class TransactionStep(ui.Component):
def __init__(self, state: State, info: list[str]) -> None:
super().__init__()
self.state = state
self.info = info
def on_render(self) -> None:
from trezor import ui # local_cache_global
state = self.state
info = self.info
ui.header("Signing transaction", ui.ICON_SEND, ui.TITLE_GREY, ui.BG, ui.BLUE)
p = 1000 * state.progress_cur // state.progress_total
ui.display.loader(p, False, -4, ui.WHITE, ui.BG)
ui.display.text_center(ui.WIDTH // 2, 210, info[0], ui.NORMAL, ui.FG, ui.BG)
if len(info) > 1:
ui.display.text_center(ui.WIDTH // 2, 235, info[1], ui.NORMAL, ui.FG, ui.BG)
class KeyImageSyncStep(ui.Component):
def __init__(self, current: int, total_num: int) -> None:
super().__init__()
self.current = current
self.total_num = total_num
def on_render(self) -> None:
current = self.current
total_num = self.total_num
ui.header("Syncing", ui.ICON_SEND, ui.TITLE_GREY, ui.BG, ui.BLUE)
p = (1000 * (current + 1) // total_num) if total_num > 0 else 0
ui.display.loader(p, False, 18, ui.WHITE, ui.BG)
class LiveRefreshStep(ui.Component):
def __init__(self, current: int) -> None:
super().__init__()
self.current = current
def on_render(self) -> None:
from trezor import ui # local_cache_global
current = self.current
ui.header("Refreshing", ui.ICON_SEND, ui.TITLE_GREY, ui.BG, ui.BLUE)
p = (1000 * current // 8) % 1000
ui.display.loader(p, True, 18, ui.WHITE, ui.BG)
ui.display.text_center(
ui.WIDTH // 2, 145, str(current), ui.NORMAL, ui.FG, ui.BG
)
async def transaction_step(state: State, step: int, sub_step: int = 0) -> None:
if step == 0:
info = ["Signing..."]
elif step == state.STEP_INP:
info = ["Processing inputs", f"{sub_step + 1}/{state.input_count}"]
elif step == state.STEP_VINI:
info = ["Hashing inputs", f"{sub_step + 1}/{state.input_count}"]
elif step == state.STEP_ALL_IN:
info = ["Processing..."]
elif step == state.STEP_OUT:
info = ["Processing outputs", f"{sub_step + 1}/{state.output_count}"]
elif step == state.STEP_ALL_OUT:
info = ["Postprocessing..."]
elif step == state.STEP_SIGN:
info = ["Signing inputs", f"{sub_step + 1}/{state.input_count}"]
else:
info = ["Processing..."]
state.progress_cur += 1
await Popup(TransactionStep(state, info))
async def keyimage_sync_step(ctx: Context, current: int | None, total_num: int) -> None:
if current is None:
return
await Popup(KeyImageSyncStep(current, total_num))
async def live_refresh_step(ctx: Context, current: int | None) -> None:
if current is None:
return
await Popup(LiveRefreshStep(current))

View File

@ -11,6 +11,7 @@ if TYPE_CHECKING:
MoneroLiveRefreshFinalAck,
MoneroLiveRefreshStartAck,
)
from trezor.ui.layouts.common import ProgressLayout
from trezor.wire import Context
from apps.common.keychain import Keychain
@ -28,6 +29,7 @@ async def live_refresh(
state = LiveRefreshState()
res = await _init_step(state, ctx, msg, keychain)
progress = layout.monero_live_refresh_progress()
while True:
step = await ctx.call_any(
res,
@ -36,7 +38,7 @@ async def live_refresh(
)
del res
if MoneroLiveRefreshStepRequest.is_type_of(step):
res = await _refresh_step(state, ctx, step)
res = _refresh_step(state, ctx, step, progress)
else:
return MoneroLiveRefreshFinalAck()
gc.collect()
@ -69,8 +71,11 @@ async def _init_step(
return MoneroLiveRefreshStartAck()
async def _refresh_step(
s: LiveRefreshState, ctx: Context, msg: MoneroLiveRefreshStepRequest
def _refresh_step(
s: LiveRefreshState,
ctx: Context,
msg: MoneroLiveRefreshStepRequest,
progress: ProgressLayout,
) -> MoneroLiveRefreshStepAck:
from trezor.messages import MoneroLiveRefreshStepAck
from trezor import log
@ -81,7 +86,7 @@ async def _refresh_step(
buff = bytearray(32 * 3)
buff_mv = memoryview(buff)
await layout.live_refresh_step(ctx, s.current_output)
progress.report((1000 * s.current_output // 8) % 1000, str(s.current_output))
s.current_output += 1
if __debug__:

View File

@ -1,6 +1,7 @@
from typing import TYPE_CHECKING
from apps.common.keychain import auto_keychain
from apps.monero.layout import MoneroTransactionProgress
if TYPE_CHECKING:
from trezor.messages import MoneroTransactionFinalAck
@ -19,6 +20,7 @@ async def sign_tx(
state = State(ctx)
mods = utils.unimport_begin()
progress = MoneroTransactionProgress()
# Splitting ctx.call() to write() and read() helps to reduce memory fragmentation
# between calls.
@ -28,7 +30,9 @@ async def sign_tx(
gc.collect()
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
result_msg, accept_msgs = await _sign_tx_dispatch(state, received_msg, keychain)
result_msg, accept_msgs = await _sign_tx_dispatch(
state, received_msg, keychain, progress
)
if accept_msgs is None:
break
@ -42,7 +46,9 @@ async def sign_tx(
return result_msg
async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
async def _sign_tx_dispatch(
state: State, msg, keychain: Keychain, progress: MoneroTransactionProgress
) -> tuple:
from trezor.enums import MessageType
from trezor import wire
@ -53,7 +59,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
return (
await step_01_init_transaction.init_transaction(
state, msg.address_n, msg.network_type, msg.tsx_data, keychain
state, msg.address_n, msg.network_type, msg.tsx_data, keychain, progress
),
(MessageType.MoneroTransactionSetInputRequest,),
)
@ -62,7 +68,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
from apps.monero.signing import step_02_set_input
return (
await step_02_set_input.set_input(state, msg.src_entr),
step_02_set_input.set_input(state, msg.src_entr, progress),
(
MessageType.MoneroTransactionSetInputRequest,
MessageType.MoneroTransactionInputViniRequest,
@ -73,8 +79,8 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
from apps.monero.signing import step_04_input_vini
return (
await step_04_input_vini.input_vini(
state, msg.src_entr, msg.vini, msg.vini_hmac, msg.orig_idx
step_04_input_vini.input_vini(
state, msg.src_entr, msg.vini, msg.vini_hmac, msg.orig_idx, progress
),
(
MessageType.MoneroTransactionInputViniRequest,
@ -86,7 +92,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
from apps.monero.signing import step_05_all_inputs_set
return (
await step_05_all_inputs_set.all_inputs_set(state),
step_05_all_inputs_set.all_inputs_set(state, progress),
(MessageType.MoneroTransactionSetOutputRequest,),
)
@ -98,8 +104,8 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
del msg
return (
await step_06_set_output.set_output(
state, dst, dst_hmac, rsig_data, is_offloaded_bp
step_06_set_output.set_output(
state, dst, dst_hmac, rsig_data, is_offloaded_bp, progress
),
(
MessageType.MoneroTransactionSetOutputRequest,
@ -111,7 +117,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
from apps.monero.signing import step_07_all_outputs_set
return (
await step_07_all_outputs_set.all_outputs_set(state),
step_07_all_outputs_set.all_outputs_set(state, progress),
(MessageType.MoneroTransactionSignInputRequest,),
)
@ -119,7 +125,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
from apps.monero.signing import step_09_sign_input
return (
await step_09_sign_input.sign_input(
step_09_sign_input.sign_input(
state,
msg.src_entr,
msg.vini,
@ -129,6 +135,7 @@ async def _sign_tx_dispatch(state: State, msg, keychain: Keychain) -> tuple:
msg.pseudo_out_alpha,
msg.spend_key,
msg.orig_idx,
progress,
),
(
MessageType.MoneroTransactionSignInputRequest,

View File

@ -17,6 +17,7 @@ if TYPE_CHECKING:
MoneroTransactionRsigData,
)
from apps.monero.layout import MoneroTransactionProgress
from apps.monero.signing.state import State
@ -26,6 +27,7 @@ async def init_transaction(
network_type: int,
tsx_data: MoneroTransactionData,
keychain,
progress: MoneroTransactionProgress,
) -> MoneroTransactionInitAck:
import gc
from apps.monero.signing import offloading_keys
@ -55,7 +57,11 @@ async def init_transaction(
# Ask for confirmation
await layout.require_confirm_transaction(
state.ctx, state, tsx_data, state.creds.network_type
state.ctx,
state,
tsx_data,
state.creds.network_type,
progress,
)
state.creds.address = None
state.creds.network_type = None

View File

@ -21,24 +21,26 @@ if TYPE_CHECKING:
MoneroTransactionSourceEntry,
MoneroTransactionSetInputAck,
)
from apps.monero.layout import MoneroTransactionProgress
from apps.monero.xmr import crypto
async def set_input(
state: State, src_entr: MoneroTransactionSourceEntry
def set_input(
state: State,
src_entr: MoneroTransactionSourceEntry,
progress: MoneroTransactionProgress,
) -> MoneroTransactionSetInputAck:
from trezor.messages import MoneroTransactionSetInputAck
from apps.monero.xmr.serialize_messages.tx_prefix import TxinToKey
from apps.monero.xmr import chacha_poly, monero, serialize
from apps.monero.signing import offloading_keys
from apps.monero import layout
state.current_input_index += 1
current_input_index = state.current_input_index # local_cache_attribute
amount = src_entr.amount # local_cache_attribute
outputs = src_entr.outputs # local_cache_attribute
await layout.transaction_step(state, state.STEP_INP, current_input_index)
progress.step(state, state.STEP_INP, current_input_index)
if state.last_step > state.STEP_INP:
raise ValueError("Invalid state transition")

View File

@ -11,16 +11,17 @@ if TYPE_CHECKING:
MoneroTransactionSourceEntry,
)
from .state import State
from apps.monero.layout import MoneroTransactionProgress
async def input_vini(
def input_vini(
state: State,
src_entr: MoneroTransactionSourceEntry,
vini_bin: bytes,
vini_hmac: bytes,
orig_idx: int,
progress: MoneroTransactionProgress,
) -> MoneroTransactionInputViniAck:
from apps.monero import layout
from apps.monero.signing import offloading_keys
from apps.monero.xmr import crypto
@ -28,7 +29,7 @@ async def input_vini(
STEP_VINI = state.STEP_VINI # local_cache_attribute
await layout.transaction_step(state, STEP_VINI, state.current_input_index + 1)
progress.step(state, STEP_VINI, state.current_input_index + 1)
if state.last_step not in (state.STEP_INP, STEP_VINI):
raise ValueError("Invalid state transition")
if state.current_input_index >= state.input_count:

View File

@ -8,16 +8,18 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from trezor.messages import MoneroTransactionAllInputsSetAck
from .state import State
from apps.monero.layout import MoneroTransactionProgress
async def all_inputs_set(state: State) -> MoneroTransactionAllInputsSetAck:
from apps.monero import layout
def all_inputs_set(
state: State, progress: MoneroTransactionProgress
) -> MoneroTransactionAllInputsSetAck:
from apps.monero.xmr import crypto
from trezor.messages import MoneroTransactionAllInputsSetAck
state.mem_trace(0)
await layout.transaction_step(state, state.STEP_ALL_IN)
progress.step(state, state.STEP_ALL_IN)
if state.last_step != state.STEP_VINI:
raise ValueError("Invalid state transition")

View File

@ -12,6 +12,7 @@ from apps.monero.xmr import crypto, crypto_helpers
if TYPE_CHECKING:
from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import BulletproofPlus
from apps.monero.layout import MoneroTransactionProgress
from trezor.messages import (
MoneroTransactionDestinationEntry,
MoneroTransactionSetOutputAck,
@ -20,15 +21,14 @@ if TYPE_CHECKING:
from .state import State
async def set_output(
def set_output(
state: State,
dst_entr: MoneroTransactionDestinationEntry,
dst_entr_hmac: bytes,
rsig_data: MoneroTransactionRsigData,
is_offloaded_bp=False,
is_offloaded_bp: bool,
progress: MoneroTransactionProgress,
) -> MoneroTransactionSetOutputAck:
from apps.monero import layout
mem_trace = state.mem_trace # local_cache_attribute
mem_trace(0, True)
@ -36,9 +36,7 @@ async def set_output(
# Progress update only for master message (skip for offloaded BP msg)
if not is_offloaded_bp:
await layout.transaction_step(
state, state.STEP_OUT, state.current_output_index + 1
)
progress.step(state, state.STEP_OUT, state.current_output_index + 1)
mem_trace(1, True)

View File

@ -8,19 +8,21 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from trezor.messages import MoneroTransactionAllOutSetAck
from apps.monero.layout import MoneroTransactionProgress
from .state import State
async def all_outputs_set(state: State) -> MoneroTransactionAllOutSetAck:
def all_outputs_set(
state: State, progress: MoneroTransactionProgress
) -> MoneroTransactionAllOutSetAck:
import gc
from apps.monero import layout
mem_trace = state.mem_trace # local_cache_attribute
mem_trace(0)
await layout.transaction_step(state, state.STEP_ALL_OUT)
mem_trace(1)
progress.step(state, state.STEP_ALL_OUT)
state.mem_trace(1)
_validate(state)
state.is_processing_offloaded = False

View File

@ -14,12 +14,13 @@ import gc
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from apps.monero.layout import MoneroTransactionProgress
from trezor.messages import MoneroTransactionSourceEntry
from trezor.messages import MoneroTransactionSignInputAck
from .state import State
async def sign_input(
def sign_input(
state: State,
src_entr: MoneroTransactionSourceEntry,
vini_bin: bytes,
@ -29,6 +30,7 @@ async def sign_input(
pseudo_out_alpha_enc: bytes,
spend_enc: bytes,
orig_idx: int,
progress: MoneroTransactionProgress,
) -> MoneroTransactionSignInputAck:
"""
:param state: transaction state
@ -44,7 +46,6 @@ async def sign_input(
:return: Generated signature MGs[i]
"""
from trezor import utils
from apps.monero import layout
from apps.monero.xmr import crypto_helpers
from apps.monero.xmr import crypto
@ -53,7 +54,7 @@ async def sign_input(
input_count = state.input_count # local_cache_attribute
outputs = src_entr.outputs # local_cache_attribute
await layout.transaction_step(state, state.STEP_SIGN, state.current_input_index + 1)
progress.step(state, state.STEP_SIGN, state.current_input_index + 1)
state.current_input_index += 1
if state.last_step not in (state.STEP_ALL_OUT, state.STEP_SIGN):

View File

@ -1144,3 +1144,15 @@ def bitcoin_progress(message: str) -> ProgressLayout:
def pin_progress(message: str, description: str) -> ProgressLayout:
return RustProgress(message.upper(), description=description)
def monero_keyimage_sync_progress() -> ProgressLayout:
return RustProgress("SYNCING")
def monero_live_refresh_progress() -> ProgressLayout:
return RustProgress("REFRESHING", description="", indeterminate=True)
def monero_transaction_progress_inner() -> ProgressLayout:
return RustProgress("SIGNING TRANSACTION", description="")