1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-08-02 03:48:58 +00:00

refactor(core/bitcoin): make use of Context omission to simplify bitcoin app

This commit is contained in:
matejcik 2023-06-26 14:47:26 +02:00
parent 8538f3a65f
commit 5a4aaa79fc
6 changed files with 68 additions and 347 deletions

View File

@ -43,7 +43,7 @@ if TYPE_CHECKING:
) -> None: ) -> None:
... ...
async def signer(self) -> None: async def signer(self) -> TxRequest:
... ...
@ -54,12 +54,8 @@ async def sign_tx(
coin: CoinInfo, coin: CoinInfo,
authorization: CoinJoinAuthorization | None = None, authorization: CoinJoinAuthorization | None = None,
) -> TxRequest: ) -> TxRequest:
from trezor.enums import RequestType
from trezor.messages import TxRequest
from trezor.wire.context import call
from ..common import BITCOIN_NAMES from ..common import BITCOIN_NAMES
from . import approvers, bitcoin, helpers, progress from . import approvers, bitcoin
approver: approvers.Approver | None = None approver: approvers.Approver | None = None
if authorization: if authorization:
@ -86,19 +82,4 @@ async def sign_tx(
signer_class = bitcoinlike.Bitcoinlike signer_class = bitcoinlike.Bitcoinlike
signer = signer_class(msg, keychain, coin, approver).signer() return await signer_class(msg, keychain, coin, approver).signer()
res: TxAckType | bool | None = None
while True:
req = signer.send(res)
if isinstance(req, tuple):
request_class, req = req
assert TxRequest.is_type_of(req)
if req.request_type == RequestType.TXFINISHED:
return req
res = await call(req, request_class)
elif isinstance(req, helpers.UiConfirm):
res = await req.confirm_dialog()
progress.progress.report_init()
else:
raise TypeError("Invalid signing instruction")

View File

@ -11,7 +11,7 @@ from apps.common import safety_checks
from .. import writers from .. import writers
from ..common import input_is_external_unverified from ..common import input_is_external_unverified
from ..keychain import SLIP44_TESTNET, validate_path_against_script_type from ..keychain import SLIP44_TESTNET, validate_path_against_script_type
from . import helpers, tx_weight from . import layout, tx_weight
from .sig_hasher import BitcoinSigHasher from .sig_hasher import BitcoinSigHasher
from .tx_info import OriginalTxInfo from .tx_info import OriginalTxInfo
@ -147,8 +147,10 @@ class BasicApprover(Approver):
self.chunkify = bool(tx.chunkify) self.chunkify = bool(tx.chunkify)
async def add_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None: async def add_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
from apps.common.paths import show_path_warning
if not validate_path_against_script_type(self.coin, txi): if not validate_path_against_script_type(self.coin, txi):
await helpers.confirm_foreign_address(txi.address_n) await show_path_warning(txi.address_n)
self.foreign_address_confirmed = True self.foreign_address_confirmed = True
await super().add_internal_input(txi, node) await super().add_internal_input(txi, node)
@ -165,6 +167,8 @@ class BasicApprover(Approver):
raise ProcessError("Transaction has changed during signing") raise ProcessError("Transaction has changed during signing")
async def _add_output(self, txo: TxOutput, script_pubkey: bytes) -> None: async def _add_output(self, txo: TxOutput, script_pubkey: bytes) -> None:
from apps.common.paths import show_path_warning
from ..common import CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES from ..common import CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES
if txo.address_n and not validate_path_against_script_type( if txo.address_n and not validate_path_against_script_type(
@ -173,7 +177,7 @@ class BasicApprover(Approver):
script_type=CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[txo.script_type], script_type=CHANGE_OUTPUT_TO_INPUT_SCRIPT_TYPES[txo.script_type],
multisig=bool(txo.multisig), multisig=bool(txo.multisig),
): ):
await helpers.confirm_foreign_address(txo.address_n) await show_path_warning(txo.address_n)
await super()._add_output(txo, script_pubkey) await super()._add_output(txo, script_pubkey)
@ -202,7 +206,7 @@ class BasicApprover(Approver):
raise ProcessError( raise ProcessError(
"Reducing original output amounts is not supported." "Reducing original output amounts is not supported."
) )
await helpers.confirm_modify_output( await layout.confirm_modify_output(
txo, orig_txo, self.coin, self.amount_unit txo, orig_txo, self.coin, self.amount_unit
) )
elif txo.amount > orig_txo.amount: elif txo.amount > orig_txo.amount:
@ -224,7 +228,7 @@ class BasicApprover(Approver):
elif txo.payment_req_index is None or self.show_payment_req_details: elif txo.payment_req_index is None or self.show_payment_req_details:
# Ask user to confirm output, unless it is part of a payment # Ask user to confirm output, unless it is part of a payment
# request, which gets confirmed separately. # request, which gets confirmed separately.
await helpers.confirm_output( await layout.confirm_output(
txo, txo,
self.coin, self.coin,
self.amount_unit, self.amount_unit,
@ -240,7 +244,7 @@ class BasicApprover(Approver):
if msg.amount is None: if msg.amount is None:
raise DataError("Missing payment request amount.") raise DataError("Missing payment request amount.")
result = await helpers.confirm_payment_request(msg, self.coin, self.amount_unit) result = await layout.confirm_payment_request(msg, self.coin, self.amount_unit)
# When user wants to see more info, the result will be False. # When user wants to see more info, the result will be False.
self.show_payment_req_details = result is False self.show_payment_req_details = result is False
@ -252,7 +256,7 @@ class BasicApprover(Approver):
title = self._replacement_title(tx_info, orig_txs) title = self._replacement_title(tx_info, orig_txs)
for orig in orig_txs: for orig in orig_txs:
await helpers.confirm_replacement(title, orig.orig_hash) await layout.confirm_replacement(title, orig.orig_hash)
def _replacement_title( def _replacement_title(
self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo] self, tx_info: TxInfo, orig_txs: list[OriginalTxInfo]
@ -277,10 +281,10 @@ class BasicApprover(Approver):
await super().approve_tx(tx_info, orig_txs) await super().approve_tx(tx_info, orig_txs)
if self.has_unverified_external_input: if self.has_unverified_external_input:
await helpers.confirm_unverified_external_input() await layout.confirm_unverified_external_input()
if tx_info.wallet_path.get_path() is None: if tx_info.wallet_path.get_path() is None:
await helpers.confirm_multiple_accounts() await layout.confirm_multiple_accounts()
fee = self.total_in - self.total_out fee = self.total_in - self.total_out
@ -299,10 +303,10 @@ class BasicApprover(Approver):
if fee > fee_threshold: if fee > fee_threshold:
if fee > 10 * fee_threshold and safety_checks.is_strict(): if fee > 10 * fee_threshold and safety_checks.is_strict():
raise DataError("The fee is unexpectedly large") raise DataError("The fee is unexpectedly large")
await helpers.confirm_feeoverthreshold(fee, coin, amount_unit) await layout.confirm_feeoverthreshold(fee, coin, amount_unit)
if self.change_count > self.MAX_SILENT_CHANGE_COUNT: if self.change_count > self.MAX_SILENT_CHANGE_COUNT:
await helpers.confirm_change_count_over_threshold(self.change_count) await layout.confirm_change_count_over_threshold(self.change_count)
if orig_txs: if orig_txs:
# Replacement transaction. # Replacement transaction.
@ -338,7 +342,7 @@ class BasicApprover(Approver):
# Not a PayJoin: Show the actual fee difference, since any difference in the fee is # Not a PayJoin: Show the actual fee difference, since any difference in the fee is
# coming entirely from the user's own funds and from decreases of external outputs. # coming entirely from the user's own funds and from decreases of external outputs.
# We consider the decreases as belonging to the user. # We consider the decreases as belonging to the user.
await helpers.confirm_modify_fee( await layout.confirm_modify_fee(
title, fee - orig_fee, fee, fee_rate, coin, amount_unit title, fee - orig_fee, fee, fee_rate, coin, amount_unit
) )
elif spending > orig_spending: elif spending > orig_spending:
@ -346,7 +350,7 @@ class BasicApprover(Approver):
# PayJoin and user is spending more: Show the increase in the user's contribution # PayJoin and user is spending more: Show the increase in the user's contribution
# to the fee, ignoring any contribution from external inputs. Decreasing of # to the fee, ignoring any contribution from external inputs. Decreasing of
# external outputs is not allowed in PayJoin, so there is no need to handle those. # external outputs is not allowed in PayJoin, so there is no need to handle those.
await helpers.confirm_modify_fee( await layout.confirm_modify_fee(
title, spending - orig_spending, fee, fee_rate, coin, amount_unit title, spending - orig_spending, fee, fee_rate, coin, amount_unit
) )
else: else:
@ -357,12 +361,12 @@ class BasicApprover(Approver):
else: else:
# Standard transaction. # Standard transaction.
if tx_info.tx.lock_time > 0: if tx_info.tx.lock_time > 0:
await helpers.confirm_nondefault_locktime( await layout.confirm_nondefault_locktime(
tx_info.tx.lock_time, tx_info.lock_time_disabled() tx_info.tx.lock_time, tx_info.lock_time_disabled()
) )
if not self.external_in: if not self.external_in:
await helpers.confirm_total( await layout.confirm_total(
total, total,
fee, fee,
fee_rate, fee_rate,
@ -371,7 +375,7 @@ class BasicApprover(Approver):
tx_info.wallet_path.get_path(), tx_info.wallet_path.get_path(),
) )
else: else:
await helpers.confirm_joint_total(spending, total, coin, amount_unit) await layout.confirm_joint_total(spending, total, coin, amount_unit)
class CoinJoinApprover(Approver): class CoinJoinApprover(Approver):

View File

@ -23,7 +23,15 @@ if TYPE_CHECKING:
from typing import Sequence from typing import Sequence
from trezor.crypto import bip32 from trezor.crypto import bip32
from trezor.messages import PrevInput, PrevOutput, PrevTx, SignTx, TxInput, TxOutput from trezor.messages import (
PrevInput,
PrevOutput,
PrevTx,
SignTx,
TxInput,
TxOutput,
TxRequest,
)
from apps.common.coininfo import CoinInfo from apps.common.coininfo import CoinInfo
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
@ -40,7 +48,7 @@ _SERIALIZED_TX_BUFFER = empty_bytearray(_MAX_SERIALIZED_CHUNK_SIZE)
class Bitcoin: class Bitcoin:
async def signer(self) -> None: async def signer(self) -> TxRequest:
progress.init( progress.init(
self.tx_info.tx, is_coinjoin=isinstance(self.approver, CoinJoinApprover) self.tx_info.tx, is_coinjoin=isinstance(self.approver, CoinJoinApprover)
) )
@ -87,9 +95,12 @@ class Bitcoin:
# Sign segwit inputs and serialize witness data. # Sign segwit inputs and serialize witness data.
await self.step6_sign_segwit_inputs() await self.step6_sign_segwit_inputs()
# Write footer and send remaining data. # Write footer and remaining data.
await self.step7_finish() await self.step7_finish()
# Return the finishing message.
return helpers.finished_request(self.tx_req)
def __init__( def __init__(
self, self,
tx: SignTx, tx: SignTx,
@ -333,7 +344,6 @@ class Bitcoin:
self.write_tx_footer(self.serialized_tx, self.tx_info.tx) self.write_tx_footer(self.serialized_tx, self.tx_info.tx)
if __debug__: if __debug__:
progress.assert_finished() progress.assert_finished()
await helpers.request_tx_finish(self.tx_req)
async def process_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None: async def process_internal_input(self, txi: TxInput, node: bip32.HDNode) -> None:
if txi.script_type not in common.INTERNAL_INPUT_SCRIPT_TYPES: if txi.script_type not in common.INTERNAL_INPUT_SCRIPT_TYPES:

View File

@ -90,10 +90,12 @@ class DecredApprover(BasicApprover):
async def add_decred_sstx_submission( async def add_decred_sstx_submission(
self, txo: TxOutput, script_pubkey: bytes self, txo: TxOutput, script_pubkey: bytes
) -> None: ) -> None:
from .layout import confirm_decred_sstx_submission
# NOTE: The following calls Approver.add_external_output(), not BasicApprover.add_external_output(). # NOTE: The following calls Approver.add_external_output(), not BasicApprover.add_external_output().
# This is needed to skip calling helpers.confirm_output(), which is what BasicApprover would do. # This is needed to skip calling helpers.confirm_output(), which is what BasicApprover would do.
await super(BasicApprover, self).add_external_output(txo, script_pubkey, None) await super(BasicApprover, self).add_external_output(txo, script_pubkey, None)
await helpers.confirm_decred_sstx_submission(txo, self.coin, self.amount_unit) await confirm_decred_sstx_submission(txo, self.coin, self.amount_unit)
class DecredSigHasher: class DecredSigHasher:
@ -293,8 +295,6 @@ class Decred(Bitcoin):
if __debug__: if __debug__:
progress.assert_finished() progress.assert_finished()
await helpers.request_tx_finish(self.tx_req)
def check_prevtx_output(self, txo_bin: PrevOutput) -> None: def check_prevtx_output(self, txo_bin: PrevOutput) -> None:
if txo_bin.decred_script_version != 0: if txo_bin.decred_script_version != 0:
raise ProcessError("Cannot use utxo that has script_version != 0") raise ProcessError("Cannot use utxo that has script_version != 0")

View File

@ -1,17 +1,13 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from trezor import utils
from trezor.enums import RequestType from trezor.enums import RequestType
from trezor.wire import DataError from trezor.wire import DataError
from trezor.wire.context import call
from .. import common from .. import common
from ..writers import TX_HASH_SIZE from ..writers import TX_HASH_SIZE
from . import layout
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Awaitable
from trezor.enums import AmountUnit
from trezor.messages import ( from trezor.messages import (
PrevInput, PrevInput,
PrevOutput, PrevOutput,
@ -24,297 +20,24 @@ if TYPE_CHECKING:
) )
from apps.common.coininfo import CoinInfo from apps.common.coininfo import CoinInfo
from apps.common.paths import Bip32Path
# Machine instructions
# ===
async def request_tx_meta(
class UiConfirm: tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = None
def confirm_dialog(self) -> Awaitable[Any]: ) -> PrevTx:
raise NotImplementedError
__eq__ = utils.obj_eq
class UiConfirmOutput(UiConfirm):
def __init__(
self,
output: TxOutput,
coin: CoinInfo,
amount_unit: AmountUnit,
output_index: int,
chunkify: bool,
):
self.output = output
self.coin = coin
self.amount_unit = amount_unit
self.output_index = output_index
self.chunkify = chunkify
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_output(
self.output,
self.coin,
self.amount_unit,
self.output_index,
self.chunkify,
)
class UiConfirmDecredSSTXSubmission(UiConfirm):
def __init__(self, output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit):
self.output = output
self.coin = coin
self.amount_unit = amount_unit
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_decred_sstx_submission(
self.output, self.coin, self.amount_unit
)
class UiConfirmPaymentRequest(UiConfirm):
def __init__(
self,
payment_req: TxAckPaymentRequest,
coin: CoinInfo,
amount_unit: AmountUnit,
):
self.payment_req = payment_req
self.amount_unit = amount_unit
self.coin = coin
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_payment_request(
self.payment_req, self.coin, self.amount_unit
)
__eq__ = utils.obj_eq
class UiConfirmReplacement(UiConfirm):
def __init__(self, title: str, txid: bytes):
self.title = title
self.txid = txid
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_replacement(self.title, self.txid)
class UiConfirmModifyOutput(UiConfirm):
def __init__(
self,
txo: TxOutput,
orig_txo: TxOutput,
coin: CoinInfo,
amount_unit: AmountUnit,
):
self.txo = txo
self.orig_txo = orig_txo
self.coin = coin
self.amount_unit = amount_unit
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_modify_output(
self.txo, self.orig_txo, self.coin, self.amount_unit
)
class UiConfirmModifyFee(UiConfirm):
def __init__(
self,
title: str,
user_fee_change: int,
total_fee_new: int,
fee_rate: float,
coin: CoinInfo,
amount_unit: AmountUnit,
):
self.title = title
self.user_fee_change = user_fee_change
self.total_fee_new = total_fee_new
self.fee_rate = fee_rate
self.coin = coin
self.amount_unit = amount_unit
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_modify_fee(
self.title,
self.user_fee_change,
self.total_fee_new,
self.fee_rate,
self.coin,
self.amount_unit,
)
class UiConfirmTotal(UiConfirm):
def __init__(
self,
spending: int,
fee: int,
fee_rate: float,
coin: CoinInfo,
amount_unit: AmountUnit,
address_n: Bip32Path | None,
):
self.spending = spending
self.fee = fee
self.fee_rate = fee_rate
self.coin = coin
self.amount_unit = amount_unit
self.address_n = address_n
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_total(
self.spending,
self.fee,
self.fee_rate,
self.coin,
self.amount_unit,
self.address_n,
)
class UiConfirmJointTotal(UiConfirm):
def __init__(
self, spending: int, total: int, coin: CoinInfo, amount_unit: AmountUnit
):
self.spending = spending
self.total = total
self.coin = coin
self.amount_unit = amount_unit
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_joint_total(
self.spending, self.total, self.coin, self.amount_unit
)
class UiConfirmFeeOverThreshold(UiConfirm):
def __init__(self, fee: int, coin: CoinInfo, amount_unit: AmountUnit):
self.fee = fee
self.coin = coin
self.amount_unit = amount_unit
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_feeoverthreshold(self.fee, self.coin, self.amount_unit)
class UiConfirmChangeCountOverThreshold(UiConfirm):
def __init__(self, change_count: int):
self.change_count = change_count
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_change_count_over_threshold(self.change_count)
class UiConfirmUnverifiedExternalInput(UiConfirm):
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_unverified_external_input()
class UiConfirmForeignAddress(UiConfirm):
def __init__(self, address_n: list):
self.address_n = address_n
def confirm_dialog(self) -> Awaitable[Any]:
from apps.common import paths
return paths.show_path_warning(self.address_n)
class UiConfirmNonDefaultLocktime(UiConfirm):
def __init__(self, lock_time: int, lock_time_disabled: bool):
self.lock_time = lock_time
self.lock_time_disabled = lock_time_disabled
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_nondefault_locktime(
self.lock_time, self.lock_time_disabled
)
class UiConfirmMultipleAccounts(UiConfirm):
def confirm_dialog(self) -> Awaitable[Any]:
return layout.confirm_multiple_accounts()
def confirm_output(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit, output_index: int, chunkify: bool) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmOutput(output, coin, amount_unit, output_index, chunkify))
def confirm_decred_sstx_submission(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmDecredSSTXSubmission(output, coin, amount_unit))
def confirm_payment_request(payment_req: TxAckPaymentRequest, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmPaymentRequest(payment_req, coin, amount_unit))
def confirm_replacement(description: str, txid: bytes) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmReplacement(description, txid))
def confirm_modify_output(txo: TxOutput, orig_txo: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmModifyOutput(txo, orig_txo, coin, amount_unit))
def confirm_modify_fee(title: str, user_fee_change: int, total_fee_new: int, fee_rate: float, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (
yield UiConfirmModifyFee(
title, user_fee_change, total_fee_new, fee_rate, coin, amount_unit
)
)
def confirm_total(spending: int, fee: int, fee_rate: float, coin: CoinInfo, amount_unit: AmountUnit, address_n: Bip32Path | None) -> Awaitable[None]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmTotal(spending, fee, fee_rate, coin, amount_unit, address_n))
def confirm_joint_total(spending: int, total: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmJointTotal(spending, total, coin, amount_unit))
def confirm_feeoverthreshold(fee: int, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmFeeOverThreshold(fee, coin, amount_unit))
def confirm_change_count_over_threshold(change_count: int) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmChangeCountOverThreshold(change_count))
def confirm_unverified_external_input() -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmUnverifiedExternalInput())
def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmForeignAddress(address_n))
def confirm_nondefault_locktime(lock_time: int, lock_time_disabled: bool) -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmNonDefaultLocktime(lock_time, lock_time_disabled))
def confirm_multiple_accounts() -> Awaitable[Any]: # type: ignore [awaitable-is-generator]
return (yield UiConfirmMultipleAccounts())
def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevTx]: # type: ignore [awaitable-is-generator]
from trezor.messages import TxAckPrevMeta from trezor.messages import TxAckPrevMeta
assert tx_req.details is not None assert tx_req.details is not None
tx_req.request_type = RequestType.TXMETA tx_req.request_type = RequestType.TXMETA
tx_req.details.tx_hash = tx_hash tx_req.details.tx_hash = tx_hash
ack = yield TxAckPrevMeta, tx_req ack = await call(tx_req, TxAckPrevMeta)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return _sanitize_tx_meta(ack.tx, coin) return _sanitize_tx_meta(ack.tx, coin)
def request_tx_extra_data( async def request_tx_extra_data(
tx_req: TxRequest, offset: int, size: int, tx_hash: bytes | None = None tx_req: TxRequest, offset: int, size: int, tx_hash: bytes | None = None
) -> Awaitable[bytearray]: # type: ignore [awaitable-is-generator] ) -> bytes:
from trezor.messages import TxAckPrevExtraData from trezor.messages import TxAckPrevExtraData
details = tx_req.details # local_cache_attribute details = tx_req.details # local_cache_attribute
@ -324,12 +47,14 @@ def request_tx_extra_data(
details.extra_data_offset = offset details.extra_data_offset = offset
details.extra_data_len = size details.extra_data_len = size
details.tx_hash = tx_hash details.tx_hash = tx_hash
ack = yield TxAckPrevExtraData, tx_req ack = await call(tx_req, TxAckPrevExtraData)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return ack.tx.extra_data_chunk return ack.tx.extra_data_chunk
def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[TxInput]: # type: ignore [awaitable-is-generator] async def request_tx_input(
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
) -> TxInput:
from trezor.messages import TxAckInput from trezor.messages import TxAckInput
assert tx_req.details is not None assert tx_req.details is not None
@ -339,24 +64,28 @@ def request_tx_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes |
else: else:
tx_req.request_type = RequestType.TXINPUT tx_req.request_type = RequestType.TXINPUT
tx_req.details.request_index = i tx_req.details.request_index = i
ack = yield TxAckInput, tx_req ack = await call(tx_req, TxAckInput)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return _sanitize_tx_input(ack.tx.input, coin) return _sanitize_tx_input(ack.tx.input, coin)
def request_tx_prev_input(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevInput]: # type: ignore [awaitable-is-generator] async def request_tx_prev_input(
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
) -> PrevInput:
from trezor.messages import TxAckPrevInput from trezor.messages import TxAckPrevInput
assert tx_req.details is not None assert tx_req.details is not None
tx_req.request_type = RequestType.TXINPUT tx_req.request_type = RequestType.TXINPUT
tx_req.details.request_index = i tx_req.details.request_index = i
tx_req.details.tx_hash = tx_hash tx_req.details.tx_hash = tx_hash
ack = yield TxAckPrevInput, tx_req ack = await call(tx_req, TxAckPrevInput)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return _sanitize_tx_prev_input(ack.tx.input, coin) return _sanitize_tx_prev_input(ack.tx.input, coin)
def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[TxOutput]: # type: ignore [awaitable-is-generator] async def request_tx_output(
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
) -> TxOutput:
from trezor.messages import TxAckOutput from trezor.messages import TxAckOutput
assert tx_req.details is not None assert tx_req.details is not None
@ -366,39 +95,40 @@ def request_tx_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes
else: else:
tx_req.request_type = RequestType.TXOUTPUT tx_req.request_type = RequestType.TXOUTPUT
tx_req.details.request_index = i tx_req.details.request_index = i
ack = yield TxAckOutput, tx_req ack = await call(tx_req, TxAckOutput)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return _sanitize_tx_output(ack.tx.output, coin) return _sanitize_tx_output(ack.tx.output, coin)
def request_tx_prev_output(tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None) -> Awaitable[PrevOutput]: # type: ignore [awaitable-is-generator] async def request_tx_prev_output(
tx_req: TxRequest, i: int, coin: CoinInfo, tx_hash: bytes | None = None
) -> PrevOutput:
from trezor.messages import TxAckPrevOutput from trezor.messages import TxAckPrevOutput
assert tx_req.details is not None assert tx_req.details is not None
tx_req.request_type = RequestType.TXOUTPUT tx_req.request_type = RequestType.TXOUTPUT
tx_req.details.request_index = i tx_req.details.request_index = i
tx_req.details.tx_hash = tx_hash tx_req.details.tx_hash = tx_hash
ack = yield TxAckPrevOutput, tx_req ack = await call(tx_req, TxAckPrevOutput)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
# return sanitize_tx_prev_output(ack.tx, coin) # no sanitize is required # return sanitize_tx_prev_output(ack.tx, coin) # no sanitize is required
return ack.tx.output return ack.tx.output
def request_payment_req(tx_req: TxRequest, i: int) -> Awaitable[TxAckPaymentRequest]: # type: ignore [awaitable-is-generator] async def request_payment_req(tx_req: TxRequest, i: int) -> TxAckPaymentRequest:
from trezor.messages import TxAckPaymentRequest from trezor.messages import TxAckPaymentRequest
assert tx_req.details is not None assert tx_req.details is not None
tx_req.request_type = RequestType.TXPAYMENTREQ tx_req.request_type = RequestType.TXPAYMENTREQ
tx_req.details.request_index = i tx_req.details.request_index = i
ack = yield TxAckPaymentRequest, tx_req ack = await call(tx_req, TxAckPaymentRequest)
_clear_tx_request(tx_req) _clear_tx_request(tx_req)
return _sanitize_payment_req(ack) return _sanitize_payment_req(ack)
def request_tx_finish(tx_req: TxRequest) -> Awaitable[None]: # type: ignore [awaitable-is-generator] def finished_request(tx_req: TxRequest) -> TxRequest:
tx_req.request_type = RequestType.TXFINISHED tx_req.request_type = RequestType.TXFINISHED
yield None, tx_req return tx_req
_clear_tx_request(tx_req)
def _clear_tx_request(tx_req: TxRequest) -> None: def _clear_tx_request(tx_req: TxRequest) -> None:

View File

@ -140,8 +140,6 @@ class ZcashV4(Bitcoinlike):
async def step7_finish(self) -> None: async def step7_finish(self) -> None:
from apps.common.writers import write_compact_size from apps.common.writers import write_compact_size
from . import helpers
serialized_tx = self.serialized_tx # local_cache_attribute serialized_tx = self.serialized_tx # local_cache_attribute
if self.serialize: if self.serialize:
@ -152,8 +150,6 @@ class ZcashV4(Bitcoinlike):
write_compact_size(serialized_tx, 0) # nShieldedOutput write_compact_size(serialized_tx, 0) # nShieldedOutput
write_compact_size(serialized_tx, 0) # nJoinSplit write_compact_size(serialized_tx, 0) # nJoinSplit
await helpers.request_tx_finish(self.tx_req)
async def sign_nonsegwit_input(self, i_sign: int) -> None: async def sign_nonsegwit_input(self, i_sign: int) -> None:
await self.sign_nonsegwit_bip143_input(i_sign) await self.sign_nonsegwit_bip143_input(i_sign)