From 5dddb06e2b1488626b9f7dc1ba2105b55c41cc79 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 11 Oct 2022 16:37:20 +0200 Subject: [PATCH] refactor(core): Replace Bitcoin signing progress functions with a class. --- core/src/apps/bitcoin/sign_tx/__init__.py | 2 +- core/src/apps/bitcoin/sign_tx/bitcoin.py | 3 +- core/src/apps/bitcoin/sign_tx/decred.py | 3 +- core/src/apps/bitcoin/sign_tx/progress.py | 219 +++++++++++----------- 4 files changed, 116 insertions(+), 111 deletions(-) diff --git a/core/src/apps/bitcoin/sign_tx/__init__.py b/core/src/apps/bitcoin/sign_tx/__init__.py index 3c94814921..e7d4aa14f1 100644 --- a/core/src/apps/bitcoin/sign_tx/__init__.py +++ b/core/src/apps/bitcoin/sign_tx/__init__.py @@ -91,6 +91,6 @@ async def sign_tx( res = await ctx.call(req, request_class) elif isinstance(req, helpers.UiConfirm): res = await req.confirm_dialog(ctx) - progress.report_init() + progress.progress.report_init() else: raise TypeError("Invalid signing instruction") diff --git a/core/src/apps/bitcoin/sign_tx/bitcoin.py b/core/src/apps/bitcoin/sign_tx/bitcoin.py index 4d7c9733d8..86e1d4c2a9 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoin.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoin.py @@ -19,7 +19,8 @@ from ..common import ( ) from ..ownership import verify_nonownership from ..verification import SignatureVerifier -from . import approvers, helpers, progress +from . import approvers, helpers +from .progress import progress from .sig_hasher import BitcoinSigHasher from .tx_info import OriginalTxInfo, TxInfo diff --git a/core/src/apps/bitcoin/sign_tx/decred.py b/core/src/apps/bitcoin/sign_tx/decred.py index d04cde3450..fc2f235c70 100644 --- a/core/src/apps/bitcoin/sign_tx/decred.py +++ b/core/src/apps/bitcoin/sign_tx/decred.py @@ -12,9 +12,10 @@ from apps.common.writers import write_compact_size from .. import multisig, scripts_decred, writers from ..common import SigHashType, ecdsa_hash_pubkey, ecdsa_sign -from . import approvers, helpers, progress +from . import approvers, helpers from .approvers import BasicApprover from .bitcoin import Bitcoin +from .progress import progress DECRED_SERIALIZE_FULL = const(0 << 16) DECRED_SERIALIZE_NO_WITNESS = const(1 << 16) diff --git a/core/src/apps/bitcoin/sign_tx/progress.py b/core/src/apps/bitcoin/sign_tx/progress.py index d68f8f8f9c..a6d8554682 100644 --- a/core/src/apps/bitcoin/sign_tx/progress.py +++ b/core/src/apps/bitcoin/sign_tx/progress.py @@ -12,123 +12,126 @@ if TYPE_CHECKING: # the input, prevtx metadata, prevtx input, prevtx output, prevtx change-output _PREV_TX_MULTIPLIER = 5 -_progress = 0 -_steps = 0 -_signing = False -_prev_tx_step = 0 +class Progress: + def __init__(self): + self.progress = 0 + self.steps = 0 + self.signing = False -def init(tx: SignTx) -> None: - global _progress, _steps, _signing - _progress = 0 - _signing = False + # We don't know how long it will take to fetch the previous transactions, + # so for each one we reserve _PREV_TX_MULTIPLIER steps in the signing + # progress. Once we fetch a prev_tx's metadata, we subdivide the reserved + # space and then prev_tx_step represents the progress of fetching one + # prev_tx input or output in the overall signing progress. + self.prev_tx_step = 0 - # Step 1 and 2 - load inputs and outputs - _steps = tx.inputs_count + tx.outputs_count + def init(self, tx: SignTx) -> None: + self.progress = 0 + self.signing = False - report_init() - report() + # Step 1 and 2 - load inputs and outputs + self.steps = tx.inputs_count + tx.outputs_count + self.report_init() + self.report() + + def init_signing( + self, + external: int, + segwit: int, + taproot_only: bool, + has_presigned: bool, + serialize: bool, + coin: CoinInfo, + tx: SignTx, + orig_txs: list[OriginalTxInfo], + ) -> None: + if __debug__: + self.assert_finished() + + self.progress = 0 + self.steps = 0 + self.signing = True + + # Step 3 - verify inputs + if taproot_only or (coin.overwintered and tx.version == 5): + if has_presigned: + self.steps += external + else: + self.steps = tx.inputs_count * _PREV_TX_MULTIPLIER + + for orig in orig_txs: + self.steps += orig.tx.inputs_count + + # Steps 3 and 4 - get_legacy_tx_digest() for each legacy input. + if not (coin.force_bip143 or coin.overwintered or coin.decred): + self.steps += (tx.inputs_count - segwit) * ( + tx.inputs_count + tx.outputs_count + ) + + if segwit != tx.inputs_count: + # The transaction has a legacy input. + + # Simplification: We assume that all original transaction inputs + # are legacy, since mixed script types are not supported in Suite. + for orig in orig_txs: + self.steps += orig.tx.inputs_count * ( + orig.tx.inputs_count + orig.tx.outputs_count + ) + + # Steps 4 and 6 - serialize and sign inputs + if serialize: + self.steps += tx.inputs_count + segwit + else: + self.steps += tx.inputs_count - external + + # Step 5 - serialize outputs + if serialize and not coin.decred: + self.steps += tx.outputs_count + + self.report_init() + self.report() + + def init_prev_tx(self, inputs: int, outputs: int) -> None: + self.prev_tx_step = _PREV_TX_MULTIPLIER / (inputs + outputs) + + def advance(self) -> None: + self.progress += 1 + self.report() + + def advance_prev_tx(self) -> None: + self.progress += self.prev_tx_step + self.report() + + def report_init(self) -> None: + from trezor import workflow + + workflow.close_others() + ui.display.clear() + if self.signing: + ui.header("Signing transaction") + else: + ui.header("Loading transaction") + + def report(self) -> None: + from trezor import utils + + if utils.DISABLE_ANIMATION: + return + p = int(1000 * self.progress / self.steps) + ui.display.loader(p, False, 18, ui.WHITE, ui.BG) -def init_signing( - external: int, - segwit: int, - taproot_only: bool, - has_presigned: bool, - serialize: bool, - coin: CoinInfo, - tx: SignTx, - orig_txs: list[OriginalTxInfo], -) -> None: if __debug__: - assert_finished() - global _progress, _steps, _signing - _progress = 0 - _steps = 0 - _signing = True + def assert_finished(self) -> None: + if abs(self.progress - self.steps) > 0.5: + from trezor import wire - # Step 3 - verify inputs - if taproot_only or (coin.overwintered and tx.version == 5): - if has_presigned: - _steps += external - else: - _steps = tx.inputs_count * _PREV_TX_MULTIPLIER - - for orig in orig_txs: - _steps += orig.tx.inputs_count - - # Steps 3 and 4 - get_legacy_tx_digest() for each legacy input. - if not (coin.force_bip143 or coin.overwintered or coin.decred): - _steps += (tx.inputs_count - segwit) * (tx.inputs_count + tx.outputs_count) - - if segwit != tx.inputs_count: - # The transaction has a legacy input. - - # Simplification: We assume that all original transaction inputs - # are legacy, since mixed script types are not supported in Suite. - for orig in orig_txs: - _steps += orig.tx.inputs_count * ( - orig.tx.inputs_count + orig.tx.outputs_count + operation = "signing" if self.signing else "loading" + raise wire.FirmwareError( + f"Transaction {operation} progress finished at {self.progress}/{self.steps}." ) - # Steps 4 and 6 - serialize and sign inputs - if serialize: - _steps += tx.inputs_count + segwit - else: - _steps += tx.inputs_count - external - # Step 5 - serialize outputs - if serialize and not coin.decred: - _steps += tx.outputs_count - - report_init() - report() - - -def init_prev_tx(inputs: int, outputs: int) -> None: - global _prev_tx_step - _prev_tx_step = _PREV_TX_MULTIPLIER / (inputs + outputs) - - -def advance() -> None: - global _progress - _progress += 1 - report() - - -def advance_prev_tx() -> None: - global _progress - _progress += _prev_tx_step - report() - - -def report_init() -> None: - from trezor import workflow - - workflow.close_others() - ui.display.clear() - if _signing: - ui.header("Signing transaction") - else: - ui.header("Loading transaction") - - -def report() -> None: - from trezor import utils - - if utils.DISABLE_ANIMATION: - return - p = int(1000 * _progress / _steps) - ui.display.loader(p, False, 18, ui.WHITE, ui.BG) - - -if __debug__: - - def assert_finished() -> None: - if abs(_progress - _steps) > 0.5: - operation = "signing" if _signing else "loading" - from trezor import wire - raise wire.FirmwareError( - f"Transaction {operation} progress finished at {_progress}/{_steps}." - ) +progress = Progress()