From 9fc5bb546bff59104fa158e53a23bc4ffa327b9c Mon Sep 17 00:00:00 2001 From: grdddj Date: Wed, 8 Dec 2021 10:10:58 +0100 Subject: [PATCH] style(core): full pyright-based type-checking Changes many fields to required -- as far as we were able to figure out, signing would fail if these fields aren't provided anyway, so this should not pose a compatibility problem. Co-authored-by: matejcik --- common/protob/messages-binance.proto | 32 +- common/protob/messages-eos.proto | 114 ++--- common/protob/messages-nem.proto | 70 +-- common/protob/messages-ripple.proto | 8 +- common/protob/messages-tezos.proto | 16 +- core/.gitignore | 1 + core/Makefile | 21 +- core/embed/extmod/rustmods/modtrezorproto.c | 4 +- core/mocks/generated/trezorproto.pyi | 4 +- core/mocks/uctypes.pyi | 4 +- core/pyrightconfig.json | 14 + core/src/all_modules.py | 2 + core/src/apps/base.py | 10 +- core/src/apps/binance/get_address.py | 9 +- core/src/apps/binance/get_public_key.py | 8 +- core/src/apps/binance/helpers.py | 20 +- core/src/apps/binance/layout.py | 25 +- core/src/apps/binance/sign_tx.py | 11 +- core/src/apps/bitcoin/addresses.py | 4 +- core/src/apps/bitcoin/authorization.py | 3 +- core/src/apps/bitcoin/authorize_coinjoin.py | 3 +- core/src/apps/bitcoin/common.py | 6 +- core/src/apps/bitcoin/get_address.py | 6 +- core/src/apps/bitcoin/get_ownership_id.py | 4 +- core/src/apps/bitcoin/get_ownership_proof.py | 4 +- core/src/apps/bitcoin/get_public_key.py | 12 +- core/src/apps/bitcoin/keychain.py | 36 +- core/src/apps/bitcoin/ownership.py | 4 +- core/src/apps/bitcoin/scripts.py | 6 +- core/src/apps/bitcoin/scripts_decred.py | 4 +- core/src/apps/bitcoin/sign_message.py | 4 +- core/src/apps/bitcoin/sign_tx/__init__.py | 4 +- core/src/apps/bitcoin/sign_tx/approvers.py | 3 +- core/src/apps/bitcoin/sign_tx/bitcoin.py | 12 +- core/src/apps/bitcoin/sign_tx/bitcoinlike.py | 4 +- core/src/apps/bitcoin/sign_tx/decred.py | 3 +- core/src/apps/bitcoin/sign_tx/helpers.py | 35 +- core/src/apps/bitcoin/sign_tx/layout.py | 3 +- core/src/apps/bitcoin/sign_tx/matchcheck.py | 6 +- core/src/apps/bitcoin/sign_tx/sig_hasher.py | 4 +- core/src/apps/bitcoin/sign_tx/tx_info.py | 5 +- core/src/apps/bitcoin/sign_tx/tx_weight.py | 3 +- core/src/apps/bitcoin/sign_tx/zcash.py | 5 +- core/src/apps/bitcoin/verification.py | 4 +- core/src/apps/bitcoin/verify_message.py | 4 +- core/src/apps/bitcoin/writers.py | 3 +- core/src/apps/cardano/address.py | 4 +- core/src/apps/cardano/auxiliary_data.py | 4 +- core/src/apps/cardano/byron_address.py | 4 +- core/src/apps/cardano/certificates.py | 4 +- core/src/apps/cardano/get_address.py | 4 +- .../apps/cardano/get_native_script_hash.py | 4 +- core/src/apps/cardano/get_public_key.py | 3 +- .../cardano/helpers/account_path_check.py | 4 +- core/src/apps/cardano/helpers/credential.py | 4 +- .../helpers/hash_builder_collection.py | 4 +- core/src/apps/cardano/helpers/utils.py | 4 +- core/src/apps/cardano/layout.py | 4 +- core/src/apps/cardano/native_script.py | 4 +- core/src/apps/cardano/seed.py | 4 +- core/src/apps/cardano/sign_tx.py | 3 +- core/src/apps/common/authorization.py | 7 +- core/src/apps/common/cbor.py | 5 +- core/src/apps/common/coininfo.py | 7 +- core/src/apps/common/coininfo.py.mako | 7 +- core/src/apps/common/keychain.py | 3 +- core/src/apps/common/paths.py | 21 +- core/src/apps/common/request_pin.py | 7 +- core/src/apps/common/seed.py | 4 +- core/src/apps/common/signverify.py | 3 +- core/src/apps/common/writers.py | 4 +- core/src/apps/debug/__init__.py | 4 +- core/src/apps/debug/load_device.py | 10 +- core/src/apps/eos/actions/__init__.py | 18 +- core/src/apps/eos/actions/layout.py | 19 +- core/src/apps/eos/get_public_key.py | 4 +- core/src/apps/eos/sign_tx.py | 6 +- core/src/apps/eos/writers.py | 13 +- core/src/apps/ethereum/get_address.py | 4 +- core/src/apps/ethereum/get_public_key.py | 3 +- core/src/apps/ethereum/helpers.py | 3 +- core/src/apps/ethereum/keychain.py | 4 +- core/src/apps/ethereum/layout.py | 4 +- core/src/apps/ethereum/networks.py | 4 +- core/src/apps/ethereum/networks.py.mako | 4 +- core/src/apps/ethereum/sign_message.py | 4 +- core/src/apps/ethereum/sign_tx.py | 4 +- core/src/apps/ethereum/sign_tx_eip1559.py | 4 +- core/src/apps/ethereum/sign_typed_data.py | 4 +- core/src/apps/ethereum/verify_message.py | 4 +- core/src/apps/homescreen/__init__.py | 4 +- core/src/apps/management/apply_flags.py | 4 +- core/src/apps/management/apply_settings.py | 4 +- core/src/apps/management/backup_device.py | 4 +- core/src/apps/management/change_pin.py | 4 +- core/src/apps/management/change_wipe_code.py | 4 +- .../management/recovery_device/__init__.py | 4 +- .../apps/management/recovery_device/layout.py | 4 +- .../management/recovery_device/recover.py | 6 +- .../apps/management/reset_device/__init__.py | 4 +- .../apps/management/reset_device/layout.py | 5 +- core/src/apps/management/sd_protect.py | 4 +- core/src/apps/management/wipe_device.py | 4 +- core/src/apps/misc/cipher_key_value.py | 8 +- core/src/apps/misc/get_ecdh_session_key.py | 3 +- core/src/apps/misc/get_entropy.py | 4 +- core/src/apps/misc/sign_identity.py | 15 +- core/src/apps/monero/layout.py | 4 +- core/src/apps/monero/misc.py | 4 +- .../apps/monero/signing/offloading_keys.py | 3 +- core/src/apps/monero/signing/state.py | 3 +- .../signing/step_01_init_transaction.py | 3 +- .../apps/monero/signing/step_02_set_input.py | 4 +- .../signing/step_03_inputs_permutation.py | 4 +- .../apps/monero/signing/step_04_input_vini.py | 4 +- .../monero/signing/step_05_all_inputs_set.py | 4 +- .../apps/monero/signing/step_06_set_output.py | 3 +- .../monero/signing/step_07_all_outputs_set.py | 3 +- .../apps/monero/signing/step_09_sign_input.py | 3 +- .../apps/monero/signing/step_10_sign_final.py | 4 +- core/src/apps/monero/xmr/addresses.py | 4 +- core/src/apps/monero/xmr/credentials.py | 4 +- core/src/apps/monero/xmr/crypto/__init__.py | 4 +- core/src/apps/monero/xmr/key_image.py | 4 +- core/src/apps/monero/xmr/mlsag.py | 3 +- core/src/apps/monero/xmr/mlsag_hasher.py | 4 +- core/src/apps/monero/xmr/monero.py | 4 +- core/src/apps/monero/xmr/range_signatures.py | 3 +- core/src/apps/monero/xmr/types.py | 4 +- core/src/apps/nem/get_address.py | 17 +- core/src/apps/nem/helpers.py | 2 +- core/src/apps/nem/layout.py | 13 +- core/src/apps/nem/mosaic/__init__.py | 19 +- core/src/apps/nem/mosaic/helpers.py | 25 +- core/src/apps/nem/mosaic/layout.py | 26 +- core/src/apps/nem/mosaic/nem_mosaics.py | 156 ++++--- core/src/apps/nem/mosaic/nem_mosaics.py.mako | 84 +++- core/src/apps/nem/mosaic/serialize.py | 28 +- core/src/apps/nem/multisig/__init__.py | 15 +- core/src/apps/nem/multisig/layout.py | 18 +- core/src/apps/nem/multisig/serialize.py | 22 +- core/src/apps/nem/namespace/__init__.py | 9 +- core/src/apps/nem/namespace/layout.py | 9 +- core/src/apps/nem/namespace/serialize.py | 2 +- core/src/apps/nem/sign_tx.py | 10 +- core/src/apps/nem/transfer/__init__.py | 23 +- core/src/apps/nem/transfer/layout.py | 73 ++- core/src/apps/nem/transfer/serialize.py | 42 +- core/src/apps/nem/validators.py | 101 +--- core/src/apps/nem/writers.py | 11 +- core/src/apps/ripple/base58_ripple.py | 10 +- core/src/apps/ripple/get_address.py | 10 +- core/src/apps/ripple/helpers.py | 2 +- core/src/apps/ripple/layout.py | 11 +- core/src/apps/ripple/serialize.py | 76 +-- core/src/apps/ripple/sign_tx.py | 30 +- core/src/apps/stellar/consts.py | 4 +- core/src/apps/stellar/get_address.py | 4 +- core/src/apps/stellar/layout.py | 4 +- core/src/apps/stellar/operations/__init__.py | 4 +- core/src/apps/stellar/operations/layout.py | 4 +- core/src/apps/stellar/operations/serialize.py | 4 +- core/src/apps/stellar/sign_tx.py | 14 +- core/src/apps/stellar/writers.py | 4 +- core/src/apps/tezos/get_address.py | 12 +- core/src/apps/tezos/get_public_key.py | 12 +- core/src/apps/tezos/helpers.py | 13 +- core/src/apps/tezos/layout.py | 33 +- core/src/apps/tezos/sign_tx.py | 82 +++- core/src/apps/webauthn/credential.py | 4 +- core/src/apps/webauthn/fido2.py | 31 +- .../src/apps/webauthn/resident_credentials.py | 5 +- core/src/apps/workflow_handlers.py | 132 +++--- core/src/storage/cache.py | 70 ++- core/src/storage/device.py | 5 +- core/src/storage/sd_salt.py | 3 +- core/src/trezor/_proto_messages.mako | 6 +- core/src/trezor/crypto/base58.py | 3 +- core/src/trezor/crypto/bech32.py | 6 +- core/src/trezor/crypto/der.py | 5 +- core/src/trezor/crypto/rlp.py | 3 +- core/src/trezor/crypto/slip39.py | 3 +- core/src/trezor/enums/__init__.py | 6 +- core/src/trezor/enums/_proto_init.mako | 6 +- core/src/trezor/log.py | 6 +- core/src/trezor/loop.py | 34 +- core/src/trezor/messages.py | 438 +++++++++--------- core/src/trezor/pin.py | 6 +- core/src/trezor/protobuf.py | 27 +- core/src/trezor/sdcard.py | 37 +- core/src/trezor/ui/__init__.py | 27 +- .../trezor/ui/components/common/confirm.py | 6 +- core/src/trezor/ui/components/common/text.py | 3 +- core/src/trezor/ui/components/tt/button.py | 15 +- core/src/trezor/ui/components/tt/checklist.py | 3 +- core/src/trezor/ui/components/tt/confirm.py | 13 +- core/src/trezor/ui/components/tt/info.py | 10 +- .../trezor/ui/components/tt/keyboard_bip39.py | 6 +- .../ui/components/tt/keyboard_slip39.py | 6 +- .../src/trezor/ui/components/tt/passphrase.py | 5 +- core/src/trezor/ui/components/tt/pin.py | 5 +- core/src/trezor/ui/components/tt/reset.py | 8 +- core/src/trezor/ui/components/tt/scroll.py | 15 +- core/src/trezor/ui/components/tt/swipe.py | 4 +- .../trezor/ui/components/tt/word_select.py | 6 +- core/src/trezor/ui/layouts/common.py | 8 +- core/src/trezor/ui/layouts/t1.py | 4 +- core/src/trezor/ui/layouts/tt/__init__.py | 34 +- core/src/trezor/ui/layouts/tt/altcoin.py | 5 +- core/src/trezor/ui/layouts/tt/recovery.py | 5 +- core/src/trezor/ui/layouts/tt/reset.py | 4 +- core/src/trezor/ui/layouts/tt/webauthn.py | 7 +- core/src/trezor/ui/loader.py | 5 +- core/src/trezor/utils.py | 21 +- core/src/trezor/wire/__init__.py | 28 +- core/src/trezor/wire/codec_v1.py | 8 +- core/src/trezor/wire/errors.py | 38 +- core/src/trezor/workflow.py | 3 +- core/src/typing.py | 3 + core/src/usb.py | 29 +- core/tests/mock_storage.py | 2 +- core/tests/test_apps.eos.check_action.py | 83 ++-- core/tests/test_apps.nem.mosaic.py | 133 +++--- core/tests/test_apps.nem.mosaic_creation.py | 55 ++- .../test_apps.nem.mosaic_supply_change.py | 31 +- ...pps.nem.multisig.aggregate_modification.py | 28 +- core/tests/test_apps.nem.multisig.py | 50 +- core/tests/test_apps.nem.namespace.py | 30 +- core/tests/test_apps.nem.transfer.py | 35 +- core/tests/test_apps.ripple.serializer.py | 10 +- core/tests/test_storage.cache.py | 7 - core/tests/test_trezor.protobuf.py | 8 +- 232 files changed, 2064 insertions(+), 1594 deletions(-) create mode 100644 core/pyrightconfig.json diff --git a/common/protob/messages-binance.proto b/common/protob/messages-binance.proto index d02076ff8..531a2bea3 100644 --- a/common/protob/messages-binance.proto +++ b/common/protob/messages-binance.proto @@ -5,6 +5,14 @@ package hw.trezor.messages.binance; option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessageBinance"; +/** XXX + +Most likely, ALL fields in this file should be `required`. We are leaving some optionals +in place, in cases where the field value continues to the JSON as a string -- on the off +chance that somebody is relying on the behavior. + +*/ + /** * Request: Ask the device for a Binance address. * @start @@ -52,12 +60,12 @@ message BinancePublicKey { */ message BinanceSignTx { repeated uint32 address_n = 1; // BIP-32-style path to derive the key from master node - optional uint32 msg_count = 2; // count of BinanceMsg to be included in this tx - optional sint64 account_number = 3; + required uint32 msg_count = 2; // count of BinanceMsg to be included in this tx + required sint64 account_number = 3; optional string chain_id = 4; optional string memo = 5; - optional sint64 sequence = 6; - optional sint64 source = 7; + required sint64 sequence = 6; + required sint64 source = 7; } /** @@ -79,13 +87,13 @@ message BinanceTransferMsg { repeated BinanceInputOutput outputs = 2; message BinanceInputOutput { - optional string address = 1; + required string address = 1; repeated BinanceCoin coins = 2; } message BinanceCoin { - optional sint64 amount = 1; - optional string denom = 2; + required sint64 amount = 1; + required string denom = 2; } } @@ -96,13 +104,13 @@ message BinanceTransferMsg { */ message BinanceOrderMsg { optional string id = 1; - optional BinanceOrderType ordertype = 2; - optional sint64 price = 3; - optional sint64 quantity = 4; + required BinanceOrderType ordertype = 2; + required sint64 price = 3; + required sint64 quantity = 4; optional string sender = 5; - optional BinanceOrderSide side = 6; + required BinanceOrderSide side = 6; optional string symbol = 7; - optional BinanceTimeInForce timeinforce = 8; + required BinanceTimeInForce timeinforce = 8; enum BinanceOrderType { OT_UNKNOWN = 0; diff --git a/common/protob/messages-eos.proto b/common/protob/messages-eos.proto index 1e455164b..fdeda0c9d 100644 --- a/common/protob/messages-eos.proto +++ b/common/protob/messages-eos.proto @@ -33,9 +33,9 @@ message EosPublicKey { */ message EosSignTx { repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node 44'/194'/0' - optional bytes chain_id = 2; // 256-bit long chain id - optional EosTxHeader header = 3; // EOS transaction header - optional uint32 num_actions = 4; // number of actions + required bytes chain_id = 2; // 256-bit long chain id + required EosTxHeader header = 3; // EOS transaction header + required uint32 num_actions = 4; // number of actions /** * Structure representing EOS transaction header @@ -65,7 +65,7 @@ message EosTxActionRequest { * @next Failure */ message EosTxActionAck { - optional EosActionCommon common = 1; + required EosActionCommon common = 1; optional EosActionTransfer transfer = 2; optional EosActionDelegate delegate = 3; optional EosActionUndelegate undelegate = 4; @@ -85,16 +85,16 @@ message EosTxActionAck { * Structure representing asset type */ message EosAsset { - optional sint64 amount = 1; - optional uint64 symbol = 2; // Lowest 8 bits used for precision. + required sint64 amount = 1; + required uint64 symbol = 2; // Lowest 8 bits used for precision. } /** * Structure representing action permission level */ message EosPermissionLevel { - optional uint64 actor = 1; - optional uint64 permission = 2; + required uint64 actor = 1; + required uint64 permission = 2; } /** @@ -111,23 +111,23 @@ message EosTxActionAck { * Structure representing auth account */ message EosAuthorizationAccount { - optional EosPermissionLevel account = 1; - optional uint32 weight = 2; + required EosPermissionLevel account = 1; + required uint32 weight = 2; } /** * Structure representing auth delays */ message EosAuthorizationWait { - optional uint32 wait_sec = 1; - optional uint32 weight = 2; + required uint32 wait_sec = 1; + required uint32 weight = 2; } /** * Structure representing authorization settings */ message EosAuthorization { - optional uint32 threshold = 1; + required uint32 threshold = 1; repeated EosAuthorizationKey keys = 2; repeated EosAuthorizationAccount accounts = 3; repeated EosAuthorizationWait waits = 4; @@ -137,8 +137,8 @@ message EosTxActionAck { * Structure representing the common part of every action */ message EosActionCommon { - optional uint64 account = 1; // Contract name - optional uint64 name = 2; // Action name + required uint64 account = 1; // Contract name + required uint64 name = 2; // Action name repeated EosPermissionLevel authorization = 3; } @@ -146,72 +146,72 @@ message EosTxActionAck { * Structure representing transfer data structure */ message EosActionTransfer { - optional uint64 sender = 1; // Asset sender - optional uint64 receiver = 2; - optional EosAsset quantity = 3; - optional string memo = 4; + required uint64 sender = 1; // Asset sender + required uint64 receiver = 2; + required EosAsset quantity = 3; + required string memo = 4; } /** * Structure representing delegation data structure */ message EosActionDelegate { - optional uint64 sender = 1; - optional uint64 receiver = 2; - optional EosAsset net_quantity = 3; // Asset format '1.0000 EOS' - optional EosAsset cpu_quantity = 4; // Asset format '1.0000 EOS' - optional bool transfer = 5; // Transfer delegated tokens or not. + required uint64 sender = 1; + required uint64 receiver = 2; + required EosAsset net_quantity = 3; // Asset format '1.0000 EOS' + required EosAsset cpu_quantity = 4; // Asset format '1.0000 EOS' + required bool transfer = 5; // Transfer delegated tokens or not. } /** * Structure representing the removal of delegated resources from `sender` */ message EosActionUndelegate { - optional uint64 sender = 1; - optional uint64 receiver = 2; - optional EosAsset net_quantity = 3; // Asset format '1.0000 EOS' - optional EosAsset cpu_quantity = 4; // Asset format '1.0000 EOS' + required uint64 sender = 1; + required uint64 receiver = 2; + required EosAsset net_quantity = 3; // Asset format '1.0000 EOS' + required EosAsset cpu_quantity = 4; // Asset format '1.0000 EOS' } /** * Structure representing fallback if undelegate wasnt executed automaticaly. */ message EosActionRefund { - optional uint64 owner = 1; + required uint64 owner = 1; } /** * Structure representing buying RAM operation for EOS tokens */ message EosActionBuyRam { - optional uint64 payer = 1; - optional uint64 receiver = 2; - optional EosAsset quantity = 3; // Asset format '1.0000 EOS' + required uint64 payer = 1; + required uint64 receiver = 2; + required EosAsset quantity = 3; // Asset format '1.0000 EOS' } /** * Structure representing buying bytes according to RAM market price. */ message EosActionBuyRamBytes { - optional uint64 payer = 1; - optional uint64 receiver = 2; - optional uint32 bytes = 3; // Number of bytes + required uint64 payer = 1; + required uint64 receiver = 2; + required uint32 bytes = 3; // Number of bytes } /** * Structure representing sell RAM */ message EosActionSellRam { - optional uint64 account = 1; - optional uint64 bytes = 2; // Number of bytes + required uint64 account = 1; + required uint64 bytes = 2; // Number of bytes } /** * Structure representing voting. Currently, there could be up to 30 producers. */ message EosActionVoteProducer { - optional uint64 voter = 1; // Voter account - optional uint64 proxy = 2; // Proxy voter account + required uint64 voter = 1; // Voter account + required uint64 proxy = 2; // Proxy voter account repeated uint64 producers = 3; // List of producers } @@ -219,47 +219,47 @@ message EosTxActionAck { * Structure representing update authorization. */ message EosActionUpdateAuth { - optional uint64 account = 1; - optional uint64 permission = 2; - optional uint64 parent = 3; - optional EosAuthorization auth = 4; + required uint64 account = 1; + required uint64 permission = 2; + required uint64 parent = 3; + required EosAuthorization auth = 4; } /** * Structure representing delete authorization. */ message EosActionDeleteAuth { - optional uint64 account = 1; - optional uint64 permission = 2; + required uint64 account = 1; + required uint64 permission = 2; } /** * Structure representing link authorization to action. */ message EosActionLinkAuth { - optional uint64 account = 1; - optional uint64 code = 2; - optional uint64 type = 3; - optional uint64 requirement = 4; + required uint64 account = 1; + required uint64 code = 2; + required uint64 type = 3; + required uint64 requirement = 4; } /** * Structure representing unlink authorization from action. */ message EosActionUnlinkAuth { - optional uint64 account = 1; - optional uint64 code = 2; - optional uint64 type = 3; + required uint64 account = 1; + required uint64 code = 2; + required uint64 type = 3; } /** * Structure representing creation of a new account. */ message EosActionNewAccount { - optional uint64 creator = 1; - optional uint64 name = 2; - optional EosAuthorization owner = 3; - optional EosAuthorization active = 4; + required uint64 creator = 1; + required uint64 name = 2; + required EosAuthorization owner = 3; + required EosAuthorization active = 4; } /** @@ -267,7 +267,7 @@ message EosTxActionAck { */ message EosActionUnknown { required uint32 data_size = 1; - optional bytes data_chunk = 2; + required bytes data_chunk = 2; } } diff --git a/common/protob/messages-nem.proto b/common/protob/messages-nem.proto index e65f2c965..9ae1de5df 100644 --- a/common/protob/messages-nem.proto +++ b/common/protob/messages-nem.proto @@ -12,9 +12,9 @@ option java_outer_classname = "TrezorMessageNem"; * @next Failure */ message NEMGetAddress { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional uint32 network = 2; // Network ID (0x68 = Mainnet, 0x98 = Testnet, 0x60 = Mijin) - optional bool show_display = 3; // Optionally show on display before sending the result + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional uint32 network = 2 [default=0x68]; // Network ID (0x68 = Mainnet, 0x98 = Testnet, 0x60 = Mijin) + optional bool show_display = 3; // Optionally show on display before sending the result } /** @@ -32,7 +32,7 @@ message NEMAddress { * @next Failure */ message NEMSignTx { - optional NEMTransactionCommon transaction = 1; // Common part of transaction + required NEMTransactionCommon transaction = 1; // Common part of transaction optional NEMTransactionCommon multisig = 2; // Common part of inner transaction for multisig transactions optional NEMTransfer transfer = 3; // Transfer transaction part optional bool cosigning = 4; // Whether cosigning or initiating the multisig transaction @@ -45,55 +45,55 @@ message NEMSignTx { * Structure representing the common part for NEM transactions */ message NEMTransactionCommon { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional uint32 network = 2; // Network ID (0x68 = Mainnet, 0x98 = Testnet, 0x60 = Mijin) - optional uint32 timestamp = 3; // Number of seconds elapsed since the creation of the nemesis block - optional uint64 fee = 4; // Fee for the transaction - optional uint32 deadline = 5; // Deadline of the transaction - optional bytes signer = 6; // Public key of the account (for multisig transactions) + repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node + optional uint32 network = 2 [default=0x68]; // Network ID (0x68 = Mainnet, 0x98 = Testnet, 0x60 = Mijin) + required uint32 timestamp = 3; // Number of seconds elapsed since the creation of the nemesis block + required uint64 fee = 4; // Fee for the transaction + required uint32 deadline = 5; // Deadline of the transaction + optional bytes signer = 6; // Public key of the account (for multisig transactions) } /** * Structure representing the transfer transaction part for NEM transactions */ message NEMTransfer { - optional string recipient = 1; // Address of the recipient - optional uint64 amount = 2; // Amount of micro NEM that is transferred - optional bytes payload = 3; // Actual message data (unencrypted) - optional bytes public_key = 4; // Public key of the recipient (for encrypted payloads) - repeated NEMMosaic mosaics = 5; // Attached mosaics + required string recipient = 1; // Address of the recipient + required uint64 amount = 2; // Amount of micro NEM that is transferred + optional bytes payload = 3 [default=""]; // Actual message data (unencrypted) + optional bytes public_key = 4; // Public key of the recipient (for encrypted payloads) + repeated NEMMosaic mosaics = 5; // Attached mosaics /** * Structure representing the mosaic attachment for NEM transfer transactions */ message NEMMosaic { - optional string namespace = 1; // Fully qualified name of the namespace - optional string mosaic = 2; // Name of the mosaic definition - optional uint64 quantity = 3; // Mosaic quantity, always given in smallest units + required string namespace = 1; // Fully qualified name of the namespace + required string mosaic = 2; // Name of the mosaic definition + required uint64 quantity = 3; // Mosaic quantity, always given in smallest units } } /** * Structure representing the provision namespace part for NEM transactions */ message NEMProvisionNamespace { - optional string namespace = 1; // New part concatenated to the parent + required string namespace = 1; // New part concatenated to the parent optional string parent = 2; // Parent namespace (for child namespaces) - optional string sink = 3; // Rental fee sink address - optional uint64 fee = 4; // Rental fee + required string sink = 3; // Rental fee sink address + required uint64 fee = 4; // Rental fee } /** * Structure representing the mosaic definition creation part for NEM transactions */ message NEMMosaicCreation { - optional NEMMosaicDefinition definition = 1; // Mosaic definition - optional string sink = 2; // Creation fee sink address - optional uint64 fee = 3; // Creation fee + required NEMMosaicDefinition definition = 1; // Mosaic definition + required string sink = 2; // Creation fee sink address + required uint64 fee = 3; // Creation fee /** * Structure representing a mosaic definition */ message NEMMosaicDefinition { optional string name = 1; // User-friendly name of the mosaic (for whitelisted mosaics) optional string ticker = 2; // Ticker of the mosaic (for whitelisted mosaics) - optional string namespace = 3; // Fully qualified name of the namespace - optional string mosaic = 4; // Name of the mosaic definition + required string namespace = 3; // Fully qualified name of the namespace + required string mosaic = 4; // Name of the mosaic definition optional uint32 divisibility = 5; // Number of decimal places that a mosaic can be divided into optional NEMMosaicLevy levy = 6; // Levy type optional uint64 fee = 7; // Levy fee (interpretation depends on levy type) @@ -103,7 +103,7 @@ message NEMSignTx { optional uint64 supply = 11; // Initial supply to create, always given in entire units optional bool mutable_supply = 12; // Mutable supply optional bool transferable = 13; // Mosaic allows transfers among accounts other than the creator - optional string description = 14; // Mosaic description + required string description = 14; // Mosaic description repeated uint32 networks = 15; // Networks that the mosaic is valid on (for whitelisted mosaics) /** * Type of levy which will be used for mosaic @@ -118,10 +118,10 @@ message NEMSignTx { * Structure representing the mosaic supply change part for NEM transactions */ message NEMMosaicSupplyChange { - optional string namespace = 1; // Fully qualified name of the namespace - optional string mosaic = 2; // Name of the mosaic definition - optional NEMSupplyChangeType type = 3; // Type of supply change - optional uint64 delta = 4; // Supply delta + required string namespace = 1; // Fully qualified name of the namespace + required string mosaic = 2; // Name of the mosaic definition + required NEMSupplyChangeType type = 3; // Type of supply change + required uint64 delta = 4; // Supply delta /** * Type of supply change which will be applied to mosaic */ @@ -140,8 +140,8 @@ message NEMSignTx { * Structure representing the cosignatory modification for aggregate modification transactions */ message NEMCosignatoryModification { - optional NEMModificationType type = 1; // Type of cosignatory modification - optional bytes public_key = 2; // Public key of the cosignatory + required NEMModificationType type = 1; // Type of cosignatory modification + required bytes public_key = 2; // Public key of the cosignatory /** * Type of cosignatory modification */ @@ -155,8 +155,8 @@ message NEMSignTx { * Structure representing the importance transfer part for NEM transactions */ message NEMImportanceTransfer { - optional NEMImportanceTransferMode mode = 1; // Mode of importance transfer - optional bytes public_key = 2; // Public key of the remote account + required NEMImportanceTransferMode mode = 1; // Mode of importance transfer + required bytes public_key = 2; // Public key of the remote account /** * Mode of importance transfer */ diff --git a/common/protob/messages-ripple.proto b/common/protob/messages-ripple.proto index 5bb661785..658e5ec23 100644 --- a/common/protob/messages-ripple.proto +++ b/common/protob/messages-ripple.proto @@ -30,11 +30,11 @@ message RippleAddress { */ message RippleSignTx { repeated uint32 address_n = 1; // BIP-32 path. For compatibility with other wallets, must be m/44'/144'/index' - optional uint64 fee = 2; // fee (in drops) for the transaction - optional uint32 flags = 3; // transaction flags - optional uint32 sequence = 4; // transaction sequence number + required uint64 fee = 2; // fee (in drops) for the transaction + optional uint32 flags = 3 [default=0]; // transaction flags + required uint32 sequence = 4; // transaction sequence number optional uint32 last_ledger_sequence = 5; // see https://developers.ripple.com/reliable-transaction-submission.html#lastledgersequence - optional RipplePayment payment = 6; // Payment transaction type + required RipplePayment payment = 6; // Payment transaction type /** * Payment transaction type diff --git a/common/protob/messages-tezos.proto b/common/protob/messages-tezos.proto index 51e29151f..07edccf6f 100644 --- a/common/protob/messages-tezos.proto +++ b/common/protob/messages-tezos.proto @@ -102,8 +102,8 @@ message TezosSignTx { optional TezosManagerTransfer transfer = 3; message TezosManagerTransfer { - optional TezosContractID destination = 1; - optional uint64 amount = 2; + required TezosContractID destination = 1; + required uint64 amount = 2; } } } @@ -138,18 +138,18 @@ message TezosSignTx { * Structure representing information for proposal */ message TezosProposalOp { - optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID - optional uint64 period = 2; + required bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID + required uint64 period = 2; repeated bytes proposals = 4; } /** * Structure representing information for ballot */ message TezosBallotOp { - optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID - optional uint64 period = 2; - optional bytes proposal = 3; - optional TezosBallotType ballot = 4; + required bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID + required uint64 period = 2; + required bytes proposal = 3; + required TezosBallotType ballot = 4; enum TezosBallotType { Yay = 0; diff --git a/core/.gitignore b/core/.gitignore index a7b33b9ea..b48f5043b 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -7,3 +7,4 @@ tests/trezor_monero_tests* .coverage .coverage.* htmlcov/ +mypy_report diff --git a/core/Makefile b/core/Makefile index 4fb955822..fb9395033 100644 --- a/core/Makefile +++ b/core/Makefile @@ -110,14 +110,19 @@ pylint: ## run pylint on application sources and tests mypy: mypy --config-file ../setup.cfg \ src/main.py \ - src/apps/bitcoin \ - src/apps/cardano \ - src/apps/ethereum \ - src/apps/management \ - src/apps/misc \ - src/apps/stellar \ - src/apps/webauthn \ - src/trezor/ui + src/apps \ + src/trezor \ + src/storage \ + --exclude src/apps/monero + +mypy_report: + mypy --config-file ../setup.cfg \ + src/main.py \ + src/apps \ + src/trezor \ + src/storage \ + --exclude src/apps/monero \ + --html-report mypy_report clippy: cd embed/rust ; cargo clippy diff --git a/core/embed/extmod/rustmods/modtrezorproto.c b/core/embed/extmod/rustmods/modtrezorproto.c index 43194a0d9..53ce74eff 100644 --- a/core/embed/extmod/rustmods/modtrezorproto.c +++ b/core/embed/extmod/rustmods/modtrezorproto.c @@ -26,12 +26,12 @@ /// from trezor.protobuf import MessageType /// T = TypeVar("T", bound=MessageType) -/// def type_for_name(name: str) -> Type[MessageType]: +/// def type_for_name(name: str) -> type[T]: /// """Find the message definition for the given protobuf name.""" STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_protobuf_type_for_name_obj, protobuf_type_for_name); -/// def type_for_wire(wire_type: int) -> Type[MessageType]: +/// def type_for_wire(wire_type: int) -> type[T]: /// """Find the message definition for the given wire type (numeric /// identifier).""" STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_protobuf_type_for_wire_obj, diff --git a/core/mocks/generated/trezorproto.pyi b/core/mocks/generated/trezorproto.pyi index 0ecc346f1..ed1f0a3f8 100644 --- a/core/mocks/generated/trezorproto.pyi +++ b/core/mocks/generated/trezorproto.pyi @@ -4,12 +4,12 @@ T = TypeVar("T", bound=MessageType) # extmod/rustmods/modtrezorproto.c -def type_for_name(name: str) -> Type[MessageType]: +def type_for_name(name: str) -> type[T]: """Find the message definition for the given protobuf name.""" # extmod/rustmods/modtrezorproto.c -def type_for_wire(wire_type: int) -> Type[MessageType]: +def type_for_wire(wire_type: int) -> type[T]: """Find the message definition for the given wire type (numeric identifier).""" diff --git a/core/mocks/uctypes.pyi b/core/mocks/uctypes.pyi index 257c34ac5..91556a52e 100644 --- a/core/mocks/uctypes.pyi +++ b/core/mocks/uctypes.pyi @@ -24,7 +24,9 @@ FLOAT32: int class struct: def __init__(self, addr: int, descriptor: dict, layout_type: int = ...) -> None: ... -def sizeof(struct: struct) -> int: ... +StructDict = dict[str, int | tuple[int, int]] + +def sizeof(struct: struct | bytearray | StructDict, endianity: int = LITTLE_ENDIAN, /) -> int: ... def addressof(obj: bytes) -> int: ... def bytes_at(addr: int, size: int) -> bytes: ... def bytearray_at(addr: int, size: int) -> bytearray: ... diff --git a/core/pyrightconfig.json b/core/pyrightconfig.json new file mode 100644 index 000000000..535740c2b --- /dev/null +++ b/core/pyrightconfig.json @@ -0,0 +1,14 @@ +{ + "include": [ + "src" + ], + "exclude": [ + "src/apps/monero", + "src/typing.py", + "src/all_modules.py" + ], + "stubPath": "mocks/generated", + "typeCheckingMode": "basic", + "pythonVersion": "3.10", + "reportMissingModuleSource": false +} diff --git a/core/src/all_modules.py b/core/src/all_modules.py index d085f089c..f2eb42d11 100644 --- a/core/src/all_modules.py +++ b/core/src/all_modules.py @@ -38,6 +38,8 @@ main import main session import session +typing +import typing usb import usb storage diff --git a/core/src/apps/base.py b/core/src/apps/base.py index 666873682..724839a48 100644 --- a/core/src/apps/base.py +++ b/core/src/apps/base.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage.cache import storage.device from trezor import config, utils, wire, workflow @@ -6,9 +8,8 @@ from trezor.messages import Success from . import workflow_handlers -if False: +if TYPE_CHECKING: from trezor import protobuf - from typing import NoReturn from trezor.messages import ( Features, Initialize, @@ -25,6 +26,7 @@ if False: def get_features() -> Features: import storage.recovery import storage.sd_salt + import storage # workaround for https://github.com/microsoft/pyright/issues/2685 from trezor import sdcard from trezor.enums import Capability @@ -130,7 +132,7 @@ async def handle_GetFeatures(ctx: wire.Context, msg: GetFeatures) -> Features: return get_features() -async def handle_Cancel(ctx: wire.Context, msg: Cancel) -> NoReturn: +async def handle_Cancel(ctx: wire.Context, msg: Cancel) -> Success: raise wire.ActionCancelled @@ -262,8 +264,6 @@ def get_pinlocked_handler( return orig_handler async def wrapper(ctx: wire.Context, msg: wire.Msg) -> protobuf.MessageType: - # mypy limitation: orig_handler is not recognized as non-None - assert orig_handler is not None await unlock_device(ctx) return await orig_handler(ctx, msg) diff --git a/core/src/apps/binance/get_address.py b/core/src/apps/binance/get_address.py index f7f54be20..910f3fa85 100644 --- a/core/src/apps/binance/get_address.py +++ b/core/src/apps/binance/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import BinanceAddress, BinanceGetAddress from trezor.ui.layouts import show_address @@ -6,9 +8,14 @@ from apps.common.keychain import Keychain, auto_keychain from .helpers import address_from_public_key +if TYPE_CHECKING: + from trezor.wire import Context + @auto_keychain(__name__) -async def get_address(ctx, msg: BinanceGetAddress, keychain: Keychain): +async def get_address( + ctx: Context, msg: BinanceGetAddress, keychain: Keychain +) -> BinanceAddress: HRP = "bnb" await paths.validate_path(ctx, keychain, msg.address_n) diff --git a/core/src/apps/binance/get_public_key.py b/core/src/apps/binance/get_public_key.py index 54735a66f..350b694c8 100644 --- a/core/src/apps/binance/get_public_key.py +++ b/core/src/apps/binance/get_public_key.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor.messages import BinanceGetPublicKey, BinancePublicKey @@ -6,9 +7,14 @@ from trezor.ui.layouts import show_pubkey from apps.common import paths from apps.common.keychain import Keychain, auto_keychain +if TYPE_CHECKING: + from trezor.wire import Context + @auto_keychain(__name__) -async def get_public_key(ctx, msg: BinanceGetPublicKey, keychain: Keychain): +async def get_public_key( + ctx: Context, msg: BinanceGetPublicKey, keychain: Keychain +) -> BinancePublicKey: await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) pubkey = node.public_key() diff --git a/core/src/apps/binance/helpers.py b/core/src/apps/binance/helpers.py index 07a23b8bb..d2467a0c2 100644 --- a/core/src/apps/binance/helpers.py +++ b/core/src/apps/binance/helpers.py @@ -1,5 +1,7 @@ from micropython import const +from typing import TYPE_CHECKING +from trezor import wire from trezor.crypto import bech32 from trezor.crypto.scripts import sha256_ripemd160 from trezor.messages import ( @@ -10,6 +12,9 @@ from trezor.messages import ( BinanceTransferMsg, ) +if TYPE_CHECKING: + from trezor.protobuf import MessageType + ENVELOPE_BLUEPRINT = '{{"account_number":"{account_number}","chain_id":"{chain_id}","data":null,"memo":"{memo}","msgs":[{msgs}],"sequence":"{sequence}","source":"{source}"}}' MSG_TRANSFER_BLUEPRINT = '{{"inputs":[{inputs}],"outputs":[{outputs}]}}' MSG_NEWORDER_BLUEPRINT = '{{"id":"{id}","ordertype":{ordertype},"price":{price},"quantity":{quantity},"sender":"{sender}","side":{side},"symbol":"{symbol}","timeinforce":{timeinforce}}}' @@ -21,7 +26,7 @@ COIN_BLUEPRINT = '{{"amount":{amount},"denom":"{denom}"}}' DECIMALS = const(8) -def produce_json_for_signing(envelope: BinanceSignTx, msg) -> str: +def produce_json_for_signing(envelope: BinanceSignTx, msg: MessageType) -> str: if BinanceTransferMsg.is_type_of(msg): json_msg = produce_transfer_json(msg) elif BinanceOrderMsg.is_type_of(msg): @@ -29,12 +34,10 @@ def produce_json_for_signing(envelope: BinanceSignTx, msg) -> str: elif BinanceCancelMsg.is_type_of(msg): json_msg = produce_cancel_json(msg) else: - raise ValueError("input message unrecognized, is of type " + type(msg).__name__) - - if envelope.source is None or envelope.source < 0: - raise ValueError("source missing or invalid") + raise wire.ProcessError("input message unrecognized") - source = envelope.source + if envelope.source < 0: + raise wire.DataError("Source is invalid") return ENVELOPE_BLUEPRINT.format( account_number=envelope.account_number, @@ -42,12 +45,12 @@ def produce_json_for_signing(envelope: BinanceSignTx, msg) -> str: memo=envelope.memo, msgs=json_msg, sequence=envelope.sequence, - source=source, + source=envelope.source, ) def produce_transfer_json(msg: BinanceTransferMsg) -> str: - def make_input_output(input_output: BinanceInputOutput): + def make_input_output(input_output: BinanceInputOutput) -> str: coins = ",".join( COIN_BLUEPRINT.format(amount=c.amount, denom=c.denom) for c in input_output.coins @@ -89,5 +92,6 @@ def address_from_public_key(pubkey: bytes, hrp: str) -> str: h = sha256_ripemd160(pubkey).digest() convertedbits = bech32.convertbits(h, 8, 5, False) + assert convertedbits is not None return bech32.bech32_encode(hrp, convertedbits, bech32.Encoding.BECH32) diff --git a/core/src/apps/binance/layout.py b/core/src/apps/binance/layout.py index f8127476b..03d0ea5e6 100644 --- a/core/src/apps/binance/layout.py +++ b/core/src/apps/binance/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.enums import BinanceOrderSide, ButtonRequestType from trezor.messages import ( BinanceCancelMsg, @@ -11,11 +13,14 @@ from trezor.ui.layouts.tt.altcoin import confirm_transfer_binance from . import helpers +if TYPE_CHECKING: + from trezor.wire import Context + -async def require_confirm_transfer(ctx, msg: BinanceTransferMsg): +async def require_confirm_transfer(ctx: Context, msg: BinanceTransferMsg) -> None: items = [] - def make_input_output_pages(msg: BinanceInputOutput, direction): + def make_input_output_pages(msg: BinanceInputOutput, direction: str) -> None: for coin in msg.coins: items.append( ( @@ -34,36 +39,36 @@ async def require_confirm_transfer(ctx, msg: BinanceTransferMsg): await confirm_transfer_binance(ctx, items) -async def require_confirm_cancel(ctx, msg: BinanceCancelMsg): +async def require_confirm_cancel(ctx: Context, msg: BinanceCancelMsg) -> None: await confirm_properties( ctx, "confirm_cancel", title="Confirm cancel", props=[ - ("Sender address:", msg.sender), - ("Pair:", msg.symbol), - ("Order ID:", msg.refid), + ("Sender address:", str(msg.sender)), + ("Pair:", str(msg.symbol)), + ("Order ID:", str(msg.refid)), ], hold=True, br_code=ButtonRequestType.SignTx, ) -async def require_confirm_order(ctx, msg: BinanceOrderMsg): +async def require_confirm_order(ctx: Context, msg: BinanceOrderMsg) -> None: if msg.side == BinanceOrderSide.BUY: side = "Buy" elif msg.side == BinanceOrderSide.SELL: side = "Sell" else: - side = "?" + side = "Unknown" await confirm_properties( ctx, "confirm_order", title="Confirm order", props=[ - ("Sender address:", msg.sender), - ("Pair:", msg.symbol), + ("Sender address:", str(msg.sender)), + ("Pair:", str(msg.symbol)), ("Side:", side), ("Quantity:", format_amount(msg.quantity, helpers.DECIMALS)), ("Price:", format_amount(msg.price, helpers.DECIMALS)), diff --git a/core/src/apps/binance/sign_tx.py b/core/src/apps/binance/sign_tx.py index d400d9556..b1230de10 100644 --- a/core/src/apps/binance/sign_tx.py +++ b/core/src/apps/binance/sign_tx.py @@ -6,6 +6,7 @@ from trezor.messages import ( BinanceCancelMsg, BinanceOrderMsg, BinanceSignedTx, + BinanceSignTx, BinanceTransferMsg, BinanceTxRequest, ) @@ -17,7 +18,9 @@ from . import helpers, layout @auto_keychain(__name__) -async def sign_tx(ctx, envelope, keychain: Keychain): +async def sign_tx( + ctx: wire.Context, envelope: BinanceSignTx, keychain: Keychain +) -> BinanceSignedTx: # create transaction message -> sign it -> create signature/pubkey message -> serialize all if envelope.msg_count > 1: raise wire.DataError("Multiple messages not supported.") @@ -34,8 +37,8 @@ async def sign_tx(ctx, envelope, keychain: Keychain): MessageType.BinanceTransferMsg, ) - if envelope.source is None or envelope.source < 0: - raise wire.DataError("Source missing or invalid.") + if envelope.source < 0: + raise wire.DataError("Source is invalid.") msg_json = helpers.produce_json_for_signing(envelope, msg) @@ -46,7 +49,7 @@ async def sign_tx(ctx, envelope, keychain: Keychain): elif BinanceCancelMsg.is_type_of(msg): await layout.require_confirm_cancel(ctx, msg) else: - raise ValueError("input message unrecognized, is of type " + type(msg).__name__) + raise wire.ProcessError("input message unrecognized") signature_bytes = generate_content_signature(msg_json.encode(), node.private_key()) diff --git a/core/src/apps/bitcoin/addresses.py b/core/src/apps/bitcoin/addresses.py index 4b25a10cc..59a8624fc 100644 --- a/core/src/apps/bitcoin/addresses.py +++ b/core/src/apps/bitcoin/addresses.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto import base58, cashaddr from trezor.crypto.curve import bip340 @@ -13,7 +15,7 @@ from .common import ecdsa_hash_pubkey, encode_bech32_address from .multisig import multisig_get_pubkeys, multisig_pubkey_index from .scripts import output_script_native_segwit, write_output_script_multisig -if False: +if TYPE_CHECKING: from trezor.crypto import bip32 diff --git a/core/src/apps/bitcoin/authorization.py b/core/src/apps/bitcoin/authorization.py index 4a360fc53..905c8edaf 100644 --- a/core/src/apps/bitcoin/authorization.py +++ b/core/src/apps/bitcoin/authorization.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.messages import AuthorizeCoinJoin @@ -7,7 +8,7 @@ from apps.common import authorization from .common import BIP32_WALLET_DEPTH -if False: +if TYPE_CHECKING: from trezor.messages import ( GetOwnershipProof, SignTx, diff --git a/core/src/apps/bitcoin/authorize_coinjoin.py b/core/src/apps/bitcoin/authorize_coinjoin.py index 31be154c8..510ee2942 100644 --- a/core/src/apps/bitcoin/authorize_coinjoin.py +++ b/core/src/apps/bitcoin/authorize_coinjoin.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import ui from trezor.messages import AuthorizeCoinJoin, Success @@ -13,7 +14,7 @@ from .common import BIP32_WALLET_DEPTH from .keychain import validate_path_against_script_type, with_keychain from .sign_tx.layout import format_coin_amount -if False: +if TYPE_CHECKING: from trezor import wire from apps.common.coininfo import CoinInfo from apps.common.keychain import Keychain diff --git a/core/src/apps/bitcoin/common.py b/core/src/apps/bitcoin/common.py index abca4e000..4ca01391d 100644 --- a/core/src/apps/bitcoin/common.py +++ b/core/src/apps/bitcoin/common.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto import bech32, bip32, der @@ -7,9 +8,9 @@ from trezor.crypto.hashlib import sha256 from trezor.enums import InputScriptType, OutputScriptType from trezor.utils import HashWriter, ensure -if False: - from enum import IntEnum +if TYPE_CHECKING: from typing import Tuple + from enum import IntEnum from apps.common.coininfo import CoinInfo from trezor.messages import TxInput else: @@ -131,6 +132,7 @@ def decode_bech32_address(prefix: str, address: str) -> Tuple[int, bytes]: witver, raw = bech32.decode(prefix, address) if witver not in _BECH32_WITVERS: raise wire.ProcessError("Invalid address witness program") + assert witver is not None assert raw is not None return witver, bytes(raw) diff --git a/core/src/apps/bitcoin/get_address.py b/core/src/apps/bitcoin/get_address.py index 26723e5f1..76059a147 100644 --- a/core/src/apps/bitcoin/get_address.py +++ b/core/src/apps/bitcoin/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import bip32 from trezor.enums import InputScriptType from trezor.messages import Address @@ -9,7 +11,7 @@ from . import addresses from .keychain import validate_path_against_script_type, with_keychain from .multisig import multisig_pubkey_index -if False: +if TYPE_CHECKING: from trezor.messages import GetAddress from trezor.messages import HDNodeType from trezor import wire @@ -62,8 +64,8 @@ async def get_address( else: address_qr = address # base58 address + multisig_xpub_magic = coin.xpub_magic if msg.multisig: - multisig_xpub_magic = coin.xpub_magic if coin.segwit and not msg.ignore_xpub_magic: if ( msg.script_type == InputScriptType.SPENDWITNESS diff --git a/core/src/apps/bitcoin/get_ownership_id.py b/core/src/apps/bitcoin/get_ownership_id.py index d95ea931e..d251bc082 100644 --- a/core/src/apps/bitcoin/get_ownership_id.py +++ b/core/src/apps/bitcoin/get_ownership_id.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.enums import InputScriptType from trezor.messages import GetOwnershipId, OwnershipId @@ -8,7 +10,7 @@ from . import addresses, common, scripts from .keychain import validate_path_against_script_type, with_keychain from .ownership import get_identifier -if False: +if TYPE_CHECKING: from apps.common.coininfo import CoinInfo from apps.common.keychain import Keychain diff --git a/core/src/apps/bitcoin/get_ownership_proof.py b/core/src/apps/bitcoin/get_ownership_proof.py index 7d44c1166..96b68b187 100644 --- a/core/src/apps/bitcoin/get_ownership_proof.py +++ b/core/src/apps/bitcoin/get_ownership_proof.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui, wire from trezor.enums import InputScriptType from trezor.messages import GetOwnershipProof, OwnershipProof @@ -9,7 +11,7 @@ from . import addresses, common, scripts from .keychain import validate_path_against_script_type, with_keychain from .ownership import generate_proof, get_identifier -if False: +if TYPE_CHECKING: from apps.common.coininfo import CoinInfo from apps.common.keychain import Keychain from .authorization import CoinJoinAuthorization diff --git a/core/src/apps/bitcoin/get_public_key.py b/core/src/apps/bitcoin/get_public_key.py index 91259bb0a..5db6a4fa5 100644 --- a/core/src/apps/bitcoin/get_public_key.py +++ b/core/src/apps/bitcoin/get_public_key.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.enums import InputScriptType from trezor.messages import HDNodeType, PublicKey @@ -5,7 +7,7 @@ from trezor.messages import HDNodeType, PublicKey from apps.common import coininfo, paths from apps.common.keychain import get_keychain -if False: +if TYPE_CHECKING: from trezor.messages import GetPublicKey @@ -34,18 +36,18 @@ async def get_public_key(ctx: wire.Context, msg: GetPublicKey) -> PublicKey: and script_type == InputScriptType.SPENDP2SHWITNESS and (msg.ignore_xpub_magic or coin.xpub_magic_segwit_p2sh is not None) ): - # TODO: resolve type: ignore below + assert coin.xpub_magic_segwit_p2sh is not None node_xpub = node.serialize_public( - coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_p2sh # type: ignore + coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_p2sh ) elif ( coin.segwit and script_type == InputScriptType.SPENDWITNESS and (msg.ignore_xpub_magic or coin.xpub_magic_segwit_native is not None) ): - # TODO: resolve type: ignore below + assert coin.xpub_magic_segwit_native is not None node_xpub = node.serialize_public( - coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_native # type: ignore + coin.xpub_magic if msg.ignore_xpub_magic else coin.xpub_magic_segwit_native ) else: raise wire.DataError("Invalid combination of coin and script_type") diff --git a/core/src/apps/bitcoin/keychain.py b/core/src/apps/bitcoin/keychain.py index d43c94c00..f2f90be2f 100644 --- a/core/src/apps/bitcoin/keychain.py +++ b/core/src/apps/bitcoin/keychain.py @@ -1,5 +1,6 @@ import gc from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.enums import InputScriptType @@ -11,27 +12,44 @@ from apps.common.paths import PATTERN_BIP44, PathSchema from . import authorization from .common import BITCOIN_NAMES -if False: - from typing import Awaitable, Callable, Iterable, TypeVar +if TYPE_CHECKING: + from typing import Awaitable, Callable, Iterable, TypeVar, Union from typing_extensions import Protocol from trezor.protobuf import MessageType + from trezor.messages import ( + AuthorizeCoinJoin, + GetAddress, + GetOwnershipId, + GetOwnershipProof, + GetPublicKey, + SignMessage, + SignTx, + VerifyMessage, + ) + from apps.common.keychain import Keychain, MsgOut, Handler from apps.common.paths import Bip32Path - class MsgWithCoinName(Protocol): - coin_name: str + BitcoinMessage = Union[ + AuthorizeCoinJoin, + GetAddress, + GetOwnershipId, + GetOwnershipProof, + GetPublicKey, + SignMessage, + SignTx, + VerifyMessage, + ] class MsgWithAddressScriptType(Protocol): - # XXX should be Bip32Path but that fails - address_n: list[int] = ... - script_type: InputScriptType = ... + address_n: Bip32Path + script_type: InputScriptType - MsgIn = TypeVar("MsgIn", bound=MsgWithCoinName) + MsgIn = TypeVar("MsgIn", bound=BitcoinMessage) HandlerWithCoinInfo = Callable[..., Awaitable[MsgOut]] - # BIP-45 for multisig: https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki PATTERN_BIP45 = "m/45'/[0-100]/change/address_index" diff --git a/core/src/apps/bitcoin/ownership.py b/core/src/apps/bitcoin/ownership.py index 40bfedb4c..7dba9976a 100644 --- a/core/src/apps/bitcoin/ownership.py +++ b/core/src/apps/bitcoin/ownership.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.crypto import bip32, hashlib, hmac from trezor.enums import InputScriptType @@ -10,7 +12,7 @@ from . import common from .scripts import read_bip322_signature_proof, write_bip322_signature_proof from .verification import SignatureVerifier -if False: +if TYPE_CHECKING: from trezor.messages import MultisigRedeemScriptType from apps.common.coininfo import CoinInfo diff --git a/core/src/apps/bitcoin/scripts.py b/core/src/apps/bitcoin/scripts.py index 2514caeea..7d17119f1 100644 --- a/core/src/apps/bitcoin/scripts.py +++ b/core/src/apps/bitcoin/scripts.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.crypto import base58, cashaddr from trezor.crypto.hashlib import sha256 @@ -23,7 +25,7 @@ from .writers import ( write_op_push, ) -if False: +if TYPE_CHECKING: from typing import Sequence from trezor.messages import MultisigRedeemScriptType, TxInput @@ -172,7 +174,7 @@ def parse_input_script_p2pkh( if len(pubkey) != n: raise ValueError except (ValueError, EOFError): - wire.DataError("Invalid scriptSig.") + raise wire.DataError("Invalid scriptSig.") return pubkey, signature, sighash_type diff --git a/core/src/apps/bitcoin/scripts_decred.py b/core/src/apps/bitcoin/scripts_decred.py index 22910ef96..3b321ad61 100644 --- a/core/src/apps/bitcoin/scripts_decred.py +++ b/core/src/apps/bitcoin/scripts_decred.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.crypto import base58 from trezor.crypto.base58 import blake256d_32 @@ -15,7 +17,7 @@ from .scripts import ( # noqa: F401 ) from .writers import op_push_length, write_bitcoin_varint, write_op_push -if False: +if TYPE_CHECKING: from trezor.messages import MultisigRedeemScriptType from apps.common.coininfo import CoinInfo diff --git a/core/src/apps/bitcoin/sign_message.py b/core/src/apps/bitcoin/sign_message.py index e9294855d..8bf7f92b4 100644 --- a/core/src/apps/bitcoin/sign_message.py +++ b/core/src/apps/bitcoin/sign_message.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import secp256k1 from trezor.enums import InputScriptType @@ -10,7 +12,7 @@ from apps.common.signverify import decode_message, message_digest from .addresses import address_short, get_address from .keychain import validate_path_against_script_type, with_keychain -if False: +if TYPE_CHECKING: from trezor.messages import SignMessage from apps.common.coininfo import CoinInfo diff --git a/core/src/apps/bitcoin/sign_tx/__init__.py b/core/src/apps/bitcoin/sign_tx/__init__.py index 55914d80e..b198cfcb8 100644 --- a/core/src/apps/bitcoin/sign_tx/__init__.py +++ b/core/src/apps/bitcoin/sign_tx/__init__.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.enums import RequestType from trezor.messages import TxRequest @@ -9,7 +11,7 @@ from . import approvers, bitcoin, helpers, progress if not utils.BITCOIN_ONLY: from . import bitcoinlike, decred, zcash -if False: +if TYPE_CHECKING: from typing import Protocol, Union from trezor.messages import ( diff --git a/core/src/apps/bitcoin/sign_tx/approvers.py b/core/src/apps/bitcoin/sign_tx/approvers.py index 56542a4e0..3e9596e52 100644 --- a/core/src/apps/bitcoin/sign_tx/approvers.py +++ b/core/src/apps/bitcoin/sign_tx/approvers.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.enums import OutputScriptType @@ -10,7 +11,7 @@ from ..keychain import validate_path_against_script_type from . import helpers, tx_weight from .tx_info import OriginalTxInfo, TxInfo -if False: +if TYPE_CHECKING: from trezor.messages import SignTx from trezor.messages import TxInput from trezor.messages import TxOutput diff --git a/core/src/apps/bitcoin/sign_tx/bitcoin.py b/core/src/apps/bitcoin/sign_tx/bitcoin.py index 7242eaaa9..dce7138f6 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoin.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoin.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto.hashlib import sha256 @@ -22,7 +23,7 @@ from . import approvers, helpers, progress from .sig_hasher import BitcoinSigHasher from .tx_info import OriginalTxInfo, TxInfo -if False: +if TYPE_CHECKING: from typing import Sequence from trezor.crypto import bip32 @@ -611,6 +612,8 @@ class Bitcoin: self.write_tx_header(h_sign, tx_info.tx, witness_marker=False) write_bitcoin_varint(h_sign, tx_info.tx.inputs_count) + txi_sign = None + node = None for i in range(tx_info.tx.inputs_count): # STAGE_REQUEST_4_INPUT in legacy txi = await helpers.request_tx_input(self.tx_req, i, self.coin, tx_hash) @@ -618,7 +621,6 @@ class Bitcoin: # Only the previous UTXO's scriptPubKey is included in h_sign. if i == index: txi_sign = txi - node = None if not script_pubkey: self.tx_info.check_input(txi) node = self.keychain.derive(txi.address_n) @@ -643,6 +645,9 @@ class Bitcoin: else: self.write_tx_input(h_sign, txi, bytes()) + if txi_sign is None: + raise RuntimeError # index >= tx_info.tx.inputs_count + write_bitcoin_varint(h_sign, tx_info.tx.outputs_count) for i in range(tx_info.tx.outputs_count): @@ -712,6 +717,7 @@ class Bitcoin: write_bitcoin_varint(txh, tx.outputs_count) + script_pubkey: bytes | None = None for i in range(tx.outputs_count): # STAGE_REQUEST_3_PREV_OUTPUT in legacy txo_bin = await helpers.request_tx_prev_output( @@ -723,6 +729,8 @@ class Bitcoin: script_pubkey = txo_bin.script_pubkey self.check_prevtx_output(txo_bin) + assert script_pubkey is not None # prev_index < tx.outputs_count + await self.write_prev_tx_footer(txh, tx, prev_hash) if ( diff --git a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py index 9cc55880c..199237e2a 100644 --- a/core/src/apps/bitcoin/sign_tx/bitcoinlike.py +++ b/core/src/apps/bitcoin/sign_tx/bitcoinlike.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.messages import PrevTx, SignTx, TxInput @@ -8,7 +10,7 @@ from ..common import NONSEGWIT_INPUT_SCRIPT_TYPES, SigHashType from . import helpers from .bitcoin import Bitcoin -if False: +if TYPE_CHECKING: from typing import Sequence 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 03c8d5609..6c189cd18 100644 --- a/core/src/apps/bitcoin/sign_tx/decred.py +++ b/core/src/apps/bitcoin/sign_tx/decred.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto.hashlib import blake256 @@ -22,7 +23,7 @@ OUTPUT_SCRIPT_NULL_SSTXCHANGE = ( b"\xBD\x76\xA9\x14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\xAC" ) -if False: +if TYPE_CHECKING: from typing import Sequence from trezor.messages import ( diff --git a/core/src/apps/bitcoin/sign_tx/helpers.py b/core/src/apps/bitcoin/sign_tx/helpers.py index 84ec7d871..72e005c15 100644 --- a/core/src/apps/bitcoin/sign_tx/helpers.py +++ b/core/src/apps/bitcoin/sign_tx/helpers.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.enums import InputScriptType, OutputScriptType, RequestType from trezor.messages import ( @@ -23,7 +25,7 @@ from .. import common from ..writers import TX_HASH_SIZE from . import layout -if False: +if TYPE_CHECKING: from typing import Any, Awaitable from trezor.enums import AmountUnit @@ -36,6 +38,8 @@ class UiConfirm: def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]: raise NotImplementedError + __eq__ = utils.obj_eq # type: ignore + class UiConfirmOutput(UiConfirm): def __init__(self, output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit): @@ -46,8 +50,6 @@ class UiConfirmOutput(UiConfirm): def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]: return layout.confirm_output(ctx, self.output, self.coin, self.amount_unit) - __eq__ = utils.obj_eq - class UiConfirmDecredSSTXSubmission(UiConfirm): def __init__(self, output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit): @@ -60,8 +62,6 @@ class UiConfirmDecredSSTXSubmission(UiConfirm): ctx, self.output, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmReplacement(UiConfirm): def __init__(self, description: str, txid: bytes): @@ -71,8 +71,6 @@ class UiConfirmReplacement(UiConfirm): def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]: return layout.confirm_replacement(ctx, self.description, self.txid) - __eq__ = utils.obj_eq - class UiConfirmModifyOutput(UiConfirm): def __init__( @@ -92,8 +90,6 @@ class UiConfirmModifyOutput(UiConfirm): ctx, self.txo, self.orig_txo, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmModifyFee(UiConfirm): def __init__( @@ -113,8 +109,6 @@ class UiConfirmModifyFee(UiConfirm): ctx, self.user_fee_change, self.total_fee_new, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmTotal(UiConfirm): def __init__( @@ -130,8 +124,6 @@ class UiConfirmTotal(UiConfirm): ctx, self.spending, self.fee, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmJointTotal(UiConfirm): def __init__( @@ -147,8 +139,6 @@ class UiConfirmJointTotal(UiConfirm): ctx, self.spending, self.total, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmFeeOverThreshold(UiConfirm): def __init__(self, fee: int, coin: CoinInfo, amount_unit: AmountUnit): @@ -161,8 +151,6 @@ class UiConfirmFeeOverThreshold(UiConfirm): ctx, self.fee, self.coin, self.amount_unit ) - __eq__ = utils.obj_eq - class UiConfirmChangeCountOverThreshold(UiConfirm): def __init__(self, change_count: int): @@ -171,8 +159,6 @@ class UiConfirmChangeCountOverThreshold(UiConfirm): def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]: return layout.confirm_change_count_over_threshold(ctx, self.change_count) - __eq__ = utils.obj_eq - class UiConfirmForeignAddress(UiConfirm): def __init__(self, address_n: list): @@ -181,8 +167,6 @@ class UiConfirmForeignAddress(UiConfirm): def confirm_dialog(self, ctx: wire.Context) -> Awaitable[Any]: return paths.show_path_warning(ctx, self.address_n) - __eq__ = utils.obj_eq - class UiConfirmNonDefaultLocktime(UiConfirm): def __init__(self, lock_time: int, lock_time_disabled: bool): @@ -194,8 +178,6 @@ class UiConfirmNonDefaultLocktime(UiConfirm): ctx, self.lock_time, self.lock_time_disabled ) - __eq__ = utils.obj_eq - def confirm_output(output: TxOutput, coin: CoinInfo, amount_unit: AmountUnit) -> Awaitable[None]: # type: ignore return (yield UiConfirmOutput(output, coin, amount_unit)) @@ -250,9 +232,9 @@ def request_tx_meta(tx_req: TxRequest, coin: CoinInfo, tx_hash: bytes | None = N return sanitize_tx_meta(ack.tx, coin) -def request_tx_extra_data( # type: ignore +def request_tx_extra_data( tx_req: TxRequest, offset: int, size: int, tx_hash: bytes | None = None -) -> Awaitable[bytearray]: +) -> Awaitable[bytearray]: # type: ignore assert tx_req.details is not None tx_req.request_type = RequestType.TXEXTRADATA tx_req.details.extra_data_offset = offset @@ -327,7 +309,8 @@ def _clear_tx_request(tx_req: TxRequest) -> None: tx_req.details.extra_data_offset = None tx_req.serialized.signature = None tx_req.serialized.signature_index = None - # mypy thinks serialized_tx is `bytes`, which doesn't support indexed assignment + # typechecker thinks serialized_tx is `bytes`, which is immutable + # we know that it is `bytearray` in reality tx_req.serialized.serialized_tx[:] = bytes() # type: ignore diff --git a/core/src/apps/bitcoin/sign_tx/layout.py b/core/src/apps/bitcoin/sign_tx/layout.py index ded51da58..8cd59e6e4 100644 --- a/core/src/apps/bitcoin/sign_tx/layout.py +++ b/core/src/apps/bitcoin/sign_tx/layout.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor import utils @@ -13,7 +14,7 @@ if not utils.BITCOIN_ONLY: from trezor.ui.layouts.tt import altcoin -if False: +if TYPE_CHECKING: from trezor import wire from trezor.messages import TxOutput from trezor.ui.layouts import LayoutType diff --git a/core/src/apps/bitcoin/sign_tx/matchcheck.py b/core/src/apps/bitcoin/sign_tx/matchcheck.py index a75bfd939..d5d19da88 100644 --- a/core/src/apps/bitcoin/sign_tx/matchcheck.py +++ b/core/src/apps/bitcoin/sign_tx/matchcheck.py @@ -1,17 +1,19 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.utils import ensure from .. import multisig from ..common import BIP32_WALLET_DEPTH -if False: +if TYPE_CHECKING: from typing import Any, Generic, TypeVar from trezor.messages import TxInput, TxOutput T = TypeVar("T") else: - # mypy cheat: Generic[T] will be `object` which is a valid parent type + # typechecker cheat: Generic[T] will be `object` which is a valid parent type Generic = [object] # type: ignore T = 0 # type: ignore diff --git a/core/src/apps/bitcoin/sign_tx/sig_hasher.py b/core/src/apps/bitcoin/sign_tx/sig_hasher.py index 1df78405d..8d6fe8724 100644 --- a/core/src/apps/bitcoin/sign_tx/sig_hasher.py +++ b/core/src/apps/bitcoin/sign_tx/sig_hasher.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto.hashlib import sha256 from trezor.messages import PrevTx, SignTx, TxInput, TxOutput from trezor.utils import HashWriter @@ -7,7 +9,7 @@ from apps.common import coininfo from .. import scripts, writers from ..common import tagged_hashwriter -if False: +if TYPE_CHECKING: from typing import Protocol, Sequence from ..common import SigHashType diff --git a/core/src/apps/bitcoin/sign_tx/tx_info.py b/core/src/apps/bitcoin/sign_tx/tx_info.py index 84a277878..ca07c6a2a 100644 --- a/core/src/apps/bitcoin/sign_tx/tx_info.py +++ b/core/src/apps/bitcoin/sign_tx/tx_info.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto.hashlib import sha256 @@ -8,7 +9,7 @@ from .. import common, writers from ..common import BIP32_WALLET_DEPTH, input_is_external from .matchcheck import MultisigFingerprintChecker, WalletPathChecker -if False: +if TYPE_CHECKING: from typing import Protocol from trezor.messages import ( PrevTx, @@ -21,7 +22,7 @@ if False: from apps.common.coininfo import CoinInfo class Signer(Protocol): - coin = ... # type: CoinInfo + coin: CoinInfo def create_hash_writer(self) -> HashWriter: ... diff --git a/core/src/apps/bitcoin/sign_tx/tx_weight.py b/core/src/apps/bitcoin/sign_tx/tx_weight.py index 14c18b396..7d5038364 100644 --- a/core/src/apps/bitcoin/sign_tx/tx_weight.py +++ b/core/src/apps/bitcoin/sign_tx/tx_weight.py @@ -6,13 +6,14 @@ # https://github.com/trezor/trezor-mcu/commit/e1fa7af1da79e86ccaae5f3cd2a6c4644f546f8a from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.enums import InputScriptType from .. import common, ownership -if False: +if TYPE_CHECKING: from trezor.messages import TxInput # transaction header size: 4 byte version diff --git a/core/src/apps/bitcoin/sign_tx/zcash.py b/core/src/apps/bitcoin/sign_tx/zcash.py index c8c2ca742..bbb16a1a8 100644 --- a/core/src/apps/bitcoin/sign_tx/zcash.py +++ b/core/src/apps/bitcoin/sign_tx/zcash.py @@ -1,5 +1,6 @@ import ustruct as struct from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto.hashlib import blake2b @@ -23,7 +24,7 @@ from ..writers import ( from . import approvers, helpers from .bitcoinlike import Bitcoinlike -if False: +if TYPE_CHECKING: from typing import Sequence from apps.common import coininfo from .sig_hasher import SigHasher @@ -119,7 +120,7 @@ class Zcashlike(Bitcoinlike): tx: SignTx, keychain: Keychain, coin: CoinInfo, - approver: approvers.Approver, + approver: approvers.Approver | None, ) -> None: ensure(coin.overwintered) super().__init__(tx, keychain, coin, approver) diff --git a/core/src/apps/bitcoin/verification.py b/core/src/apps/bitcoin/verification.py index 6d8faa7ea..aec36c15d 100644 --- a/core/src/apps/bitcoin/verification.py +++ b/core/src/apps/bitcoin/verification.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import utils, wire from trezor.crypto import der from trezor.crypto.curve import bip340, secp256k1 @@ -19,7 +21,7 @@ from .scripts import ( write_input_script_p2wsh_in_p2sh, ) -if False: +if TYPE_CHECKING: from typing import Sequence from apps.common.coininfo import CoinInfo diff --git a/core/src/apps/bitcoin/verify_message.py b/core/src/apps/bitcoin/verify_message.py index 95b439b9f..91c0bf672 100644 --- a/core/src/apps/bitcoin/verify_message.py +++ b/core/src/apps/bitcoin/verify_message.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import secp256k1 from trezor.enums import InputScriptType @@ -15,7 +17,7 @@ from .addresses import ( address_to_cashaddr, ) -if False: +if TYPE_CHECKING: from trezor.messages import VerifyMessage diff --git a/core/src/apps/bitcoin/writers.py b/core/src/apps/bitcoin/writers.py index f1284b19a..f379cb92f 100644 --- a/core/src/apps/bitcoin/writers.py +++ b/core/src/apps/bitcoin/writers.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor.crypto.hashlib import sha256 from trezor.utils import ensure @@ -14,7 +15,7 @@ from apps.common.writers import ( # noqa: F401 write_uint64_le, ) -if False: +if TYPE_CHECKING: from trezor.messages import ( PrevInput, PrevOutput, diff --git a/core/src/apps/cardano/address.py b/core/src/apps/cardano/address.py index 2ce8890dc..67c9f15ab 100644 --- a/core/src/apps/cardano/address.py +++ b/core/src/apps/cardano/address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import base58 from trezor.enums import CardanoAddressType @@ -15,7 +17,7 @@ from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT from .helpers.utils import get_public_key_hash, variable_length_encode from .seed import is_byron_path, is_shelley_path -if False: +if TYPE_CHECKING: from typing import Any from trezor.messages import ( diff --git a/core/src/apps/cardano/auxiliary_data.py b/core/src/apps/cardano/auxiliary_data.py index c8638edc2..e16b66bbe 100644 --- a/core/src/apps/cardano/auxiliary_data.py +++ b/core/src/apps/cardano/auxiliary_data.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import hashlib from trezor.crypto.curve import ed25519 from trezor.enums import CardanoAddressType, CardanoTxAuxiliaryDataSupplementType @@ -16,7 +18,7 @@ from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT from .helpers.utils import derive_public_key from .layout import confirm_catalyst_registration, show_auxiliary_data_hash -if False: +if TYPE_CHECKING: from typing import Union from trezor import wire diff --git a/core/src/apps/cardano/byron_address.py b/core/src/apps/cardano/byron_address.py index 8e4bc6f4f..41386c1e2 100644 --- a/core/src/apps/cardano/byron_address.py +++ b/core/src/apps/cardano/byron_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import log from trezor.crypto import crc, hashlib @@ -6,7 +8,7 @@ from apps.common import cbor from .helpers import INVALID_ADDRESS, NETWORK_MISMATCH, protocol_magics from .helpers.utils import derive_public_key -if False: +if TYPE_CHECKING: from . import seed PROTOCOL_MAGIC_KEY = 2 diff --git a/core/src/apps/cardano/certificates.py b/core/src/apps/cardano/certificates.py index 4089d8342..45f9670bf 100644 --- a/core/src/apps/cardano/certificates.py +++ b/core/src/apps/cardano/certificates.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.enums import ( CardanoCertificateType, CardanoPoolRelayType, @@ -15,7 +17,7 @@ from .helpers import ADDRESS_KEY_HASH_SIZE, INVALID_CERTIFICATE, LOVELACE_MAX_SU from .helpers.paths import SCHEMA_STAKING_ANY_ACCOUNT from .helpers.utils import validate_stake_credential -if False: +if TYPE_CHECKING: from typing import Any from trezor.messages import ( diff --git a/core/src/apps/cardano/get_address.py b/core/src/apps/cardano/get_address.py index ed66f8fa6..14e12b165 100644 --- a/core/src/apps/cardano/get_address.py +++ b/core/src/apps/cardano/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import log, wire from trezor.messages import CardanoAddress @@ -7,7 +9,7 @@ from .helpers.credential import Credential, should_show_address_credentials from .layout import show_cardano_address, show_credentials from .sign_tx import validate_network_info -if False: +if TYPE_CHECKING: from trezor.messages import ( CardanoAddressParametersType, CardanoGetAddress, diff --git a/core/src/apps/cardano/get_native_script_hash.py b/core/src/apps/cardano/get_native_script_hash.py index b6a4c6096..7ebb5298a 100644 --- a/core/src/apps/cardano/get_native_script_hash.py +++ b/core/src/apps/cardano/get_native_script_hash.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.enums import CardanoNativeScriptHashDisplayFormat from trezor.messages import CardanoNativeScriptHash @@ -5,7 +7,7 @@ from trezor.messages import CardanoNativeScriptHash from . import native_script, seed from .layout import show_native_script, show_script_hash -if False: +if TYPE_CHECKING: from trezor.messages import CardanoGetNativeScriptHash diff --git a/core/src/apps/cardano/get_public_key.py b/core/src/apps/cardano/get_public_key.py index cd4351445..6f8983b52 100644 --- a/core/src/apps/cardano/get_public_key.py +++ b/core/src/apps/cardano/get_public_key.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor import log, wire @@ -10,7 +11,7 @@ from . import seed from .helpers.paths import SCHEMA_MINT, SCHEMA_PUBKEY from .helpers.utils import derive_public_key -if False: +if TYPE_CHECKING: from trezor.messages import CardanoGetPublicKey diff --git a/core/src/apps/cardano/helpers/account_path_check.py b/core/src/apps/cardano/helpers/account_path_check.py index d65bf3150..96bb20b62 100644 --- a/core/src/apps/cardano/helpers/account_path_check.py +++ b/core/src/apps/cardano/helpers/account_path_check.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from ...common.paths import HARDENED from ..seed import is_byron_path, is_minting_path, is_multisig_path, is_shelley_path from . import ( @@ -9,7 +11,7 @@ from . import ( from .paths import ACCOUNT_PATH_INDEX, ACCOUNT_PATH_LENGTH from .utils import to_account_path -if False: +if TYPE_CHECKING: from trezor import wire from trezor.messages import ( CardanoPoolOwner, diff --git a/core/src/apps/cardano/helpers/credential.py b/core/src/apps/cardano/helpers/credential.py index 644b2076d..3417e4c84 100644 --- a/core/src/apps/cardano/helpers/credential.py +++ b/core/src/apps/cardano/helpers/credential.py @@ -1,10 +1,12 @@ +from typing import TYPE_CHECKING + from trezor.enums import CardanoAddressType from ...common.paths import address_n_to_str from .paths import CHAIN_STAKING_KEY, SCHEMA_PAYMENT, SCHEMA_STAKING from .utils import format_key_hash, format_script_hash, to_account_path -if False: +if TYPE_CHECKING: from trezor.messages import ( CardanoBlockchainPointerType, CardanoAddressParametersType, diff --git a/core/src/apps/cardano/helpers/hash_builder_collection.py b/core/src/apps/cardano/helpers/hash_builder_collection.py index 6a582468c..1dae0b87c 100644 --- a/core/src/apps/cardano/helpers/hash_builder_collection.py +++ b/core/src/apps/cardano/helpers/hash_builder_collection.py @@ -1,6 +1,8 @@ +from typing import TYPE_CHECKING + from apps.common import cbor -if False: +if TYPE_CHECKING: from typing import Any, Generic, TypeVar from trezor.utils import HashContext diff --git a/core/src/apps/cardano/helpers/utils.py b/core/src/apps/cardano/helpers/utils.py index 706e2d0bc..54b4b4b98 100644 --- a/core/src/apps/cardano/helpers/utils.py +++ b/core/src/apps/cardano/helpers/utils.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import hashlib from trezor.enums import CardanoTxSigningMode @@ -10,7 +12,7 @@ from apps.common.seed import remove_ed25519_prefix from . import ADDRESS_KEY_HASH_SIZE, SCRIPT_HASH_SIZE, bech32 -if False: +if TYPE_CHECKING: from trezor import wire from .. import seed diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py index f34da5965..6f4b14c18 100644 --- a/core/src/apps/cardano/layout.py +++ b/core/src/apps/cardano/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui from trezor.enums import ( ButtonRequestType, @@ -35,7 +37,7 @@ from .helpers.utils import ( ) from .seed import is_minting_path, is_multisig_path -if False: +if TYPE_CHECKING: from trezor import wire from trezor.messages import ( CardanoNativeScript, diff --git a/core/src/apps/cardano/native_script.py b/core/src/apps/cardano/native_script.py index a0cb5788c..a6df35060 100644 --- a/core/src/apps/cardano/native_script.py +++ b/core/src/apps/cardano/native_script.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import hashlib from trezor.enums import CardanoAddressType, CardanoNativeScriptType @@ -12,7 +14,7 @@ from .helpers.paths import SCHEMA_MINT from .helpers.utils import get_public_key_hash from .seed import Keychain, is_multisig_path -if False: +if TYPE_CHECKING: from typing import Any from trezor.messages import CardanoNativeScript diff --git a/core/src/apps/cardano/seed.py b/core/src/apps/cardano/seed.py index 47f11e8c8..f5b845ef6 100644 --- a/core/src/apps/cardano/seed.py +++ b/core/src/apps/cardano/seed.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from storage import cache, device from trezor import wire from trezor.crypto import bip32, cardano @@ -8,7 +10,7 @@ from apps.common.seed import derive_and_store_roots, get_seed from .helpers import paths -if False: +if TYPE_CHECKING: from typing import Callable, Awaitable, TypeVar, Union from apps.common.paths import Bip32Path diff --git a/core/src/apps/cardano/sign_tx.py b/core/src/apps/cardano/sign_tx.py index ba6b7c6c7..b561e35a8 100644 --- a/core/src/apps/cardano/sign_tx.py +++ b/core/src/apps/cardano/sign_tx.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import log, wire from trezor.crypto import hashlib @@ -105,7 +106,7 @@ from .layout import ( ) from .seed import is_byron_path, is_multisig_path, is_shelley_path -if False: +if TYPE_CHECKING: from typing import Any, Union from apps.common.paths import PathSchema diff --git a/core/src/apps/common/authorization.py b/core/src/apps/common/authorization.py index 4bba8edc9..5e084099e 100644 --- a/core/src/apps/common/authorization.py +++ b/core/src/apps/common/authorization.py @@ -1,11 +1,10 @@ +from typing import Iterable + import storage.cache from trezor import protobuf from trezor.enums import MessageType from trezor.utils import ensure -if False: - from typing import Iterable - WIRE_TYPES: dict[int, tuple[int, ...]] = { MessageType.AuthorizeCoinJoin: (MessageType.SignTx, MessageType.GetOwnershipProof), } @@ -21,7 +20,7 @@ def set(auth_message: protobuf.MessageType) -> None: # only wire-level messages can be stored as authorization # (because only wire-level messages have wire_type, which we use as identifier) ensure(auth_message.MESSAGE_WIRE_TYPE is not None) - assert auth_message.MESSAGE_WIRE_TYPE is not None # so that mypy knows as well + assert auth_message.MESSAGE_WIRE_TYPE is not None # so that typechecker knows too storage.cache.set( storage.cache.APP_COMMON_AUTHORIZATION_TYPE, auth_message.MESSAGE_WIRE_TYPE.to_bytes(2, "big"), diff --git a/core/src/apps/common/cbor.py b/core/src/apps/common/cbor.py index 14932cc32..954e759e7 100644 --- a/core/src/apps/common/cbor.py +++ b/core/src/apps/common/cbor.py @@ -4,12 +4,13 @@ Minimalistic CBOR implementation, supports only what we need in cardano. import ustruct as struct from micropython import const +from typing import TYPE_CHECKING from trezor import log, utils from . import readers -if False: +if TYPE_CHECKING: from typing import Any, Generic, Iterator, Tuple, TypeVar, Union K = TypeVar("K") @@ -17,7 +18,7 @@ if False: Value = Any CborSequence = Union[list[Value], Tuple[Value, ...]] else: - # mypy cheat: Generic[K, V] will be `object` which is a valid parent type + # typechecker cheat: Generic[K, V] will be `object` which is a valid parent type Generic = {(0, 0): object} # type: ignore K = V = 0 # type: ignore diff --git a/core/src/apps/common/coininfo.py b/core/src/apps/common/coininfo.py index e00ef8b45..383af8927 100644 --- a/core/src/apps/common/coininfo.py +++ b/core/src/apps/common/coininfo.py @@ -1,12 +1,11 @@ # generated from coininfo.py.mako # do not edit manually! +from typing import Any + from trezor import utils from trezor.crypto.base58 import blake256d_32, groestl512d_32, keccak_32, sha256d_32 from trezor.crypto.scripts import blake256_ripemd160, sha256_ripemd160 -if False: - from typing import Any, Type - # flake8: noqa @@ -69,7 +68,7 @@ class CoinInfo: if curve_name == "secp256k1-groestl": self.b58_hash = groestl512d_32 self.sign_hash_double = False - self.script_hash: Type[utils.HashContext] = sha256_ripemd160 + self.script_hash: type[utils.HashContext] = sha256_ripemd160 elif curve_name == "secp256k1-decred": self.b58_hash = blake256d_32 self.sign_hash_double = False diff --git a/core/src/apps/common/coininfo.py.mako b/core/src/apps/common/coininfo.py.mako index 80212a364..c9b4b9703 100644 --- a/core/src/apps/common/coininfo.py.mako +++ b/core/src/apps/common/coininfo.py.mako @@ -1,12 +1,11 @@ # generated from coininfo.py.mako # do not edit manually! +from typing import Any + from trezor import utils from trezor.crypto.base58 import blake256d_32, groestl512d_32, keccak_32, sha256d_32 from trezor.crypto.scripts import blake256_ripemd160, sha256_ripemd160 -if False: - from typing import Any, Type - # flake8: noqa @@ -69,7 +68,7 @@ class CoinInfo: if curve_name == "secp256k1-groestl": self.b58_hash = groestl512d_32 self.sign_hash_double = False - self.script_hash: Type[utils.HashContext] = sha256_ripemd160 + self.script_hash: type[utils.HashContext] = sha256_ripemd160 elif curve_name == "secp256k1-decred": self.b58_hash = blake256d_32 self.sign_hash_double = False diff --git a/core/src/apps/common/keychain.py b/core/src/apps/common/keychain.py index 52d4a669f..22ae6f815 100644 --- a/core/src/apps/common/keychain.py +++ b/core/src/apps/common/keychain.py @@ -1,4 +1,5 @@ import sys +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto import bip32 @@ -6,7 +7,7 @@ from trezor.crypto import bip32 from . import paths, safety_checks from .seed import Slip21Node, get_seed -if False: +if TYPE_CHECKING: from typing import ( Any, Awaitable, diff --git a/core/src/apps/common/paths.py b/core/src/apps/common/paths.py index 8c0a157f5..2a263d3c1 100644 --- a/core/src/apps/common/paths.py +++ b/core/src/apps/common/paths.py @@ -1,8 +1,9 @@ from micropython import const +from typing import TYPE_CHECKING HARDENED = const(0x8000_0000) -if False: +if TYPE_CHECKING: from typing import ( Any, Callable, @@ -17,7 +18,7 @@ if False: Bip32Path = Sequence[int] Slip21Path = Sequence[bytes] - PathType = TypeVar("PathType", Bip32Path, Slip21Path) + PathType = TypeVar("PathType", Bip32Path, Slip21Path, contravariant=True) class PathSchemaType(Protocol): def match(self, path: Bip32Path) -> bool: @@ -105,7 +106,7 @@ class PathSchema: _EMPTY_TUPLE = () @staticmethod - def _parse_hardened(s: str) -> int: + def _parse_hardened(s: str | int) -> int: return int(s) | HARDENED @staticmethod @@ -259,7 +260,8 @@ class PathSchema: prime = "'" if a & HARDENED else "" components.append(f"[{unharden(a)}-{unharden(b)}]{prime}") else: - # mypy thinks component is a Contanier but we're using it as a Collection. + # typechecker thinks component is a Contanier but we're using it + # as a Collection. # Which in practice it is, the only non-Collection is Interval. # But we're not going to introduce an additional type requirement # for the sake of __repr__ that doesn't exist in production anyway @@ -282,25 +284,18 @@ class PathSchema: return "" -class _AlwaysMatchingSchema: +class AlwaysMatchingSchema: @staticmethod def match(path: Bip32Path) -> bool: return True -class _NeverMatchingSchema: +class NeverMatchingSchema: @staticmethod def match(path: Bip32Path) -> bool: return False -# type objects _AlwaysMatchingSchema and _NeverMatching schema conform to the -# PathSchemaType protocol, but mypy fails to recognize this due to: -# https://github.com/python/mypy/issues/4536, -# hence the following trickery -AlwaysMatchingSchema: PathSchemaType = _AlwaysMatchingSchema # type: ignore -NeverMatchingSchema: PathSchemaType = _NeverMatchingSchema # type: ignore - # BIP-44 for basic (legacy) Bitcoin accounts, and widely used for other currencies: # https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki PATTERN_BIP44 = "m/44'/coin_type'/account'/change/address_index" diff --git a/core/src/apps/common/request_pin.py b/core/src/apps/common/request_pin.py index af11bcb62..84f3b70eb 100644 --- a/core/src/apps/common/request_pin.py +++ b/core/src/apps/common/request_pin.py @@ -1,4 +1,5 @@ import utime +from typing import Any, NoReturn import storage.cache import storage.sd_salt @@ -6,9 +7,6 @@ from trezor import config, wire from .sdcard import SdCardUnavailable, request_sd_salt -if False: - from typing import Any, NoReturn - def can_lock_device() -> bool: """Return True if the device has a PIN set or SD-protect enabled.""" @@ -108,7 +106,8 @@ async def verify_user_pin( raise RuntimeError while retry: - pin = await request_pin_on_device( + # request_pin_on_device possibly unbound + pin = await request_pin_on_device( # type: ignore ctx, "Wrong PIN, enter again", config.get_pin_rem(), allow_cancel ) if config.unlock(pin, salt): diff --git a/core/src/apps/common/seed.py b/core/src/apps/common/seed.py index 56bf554e4..fce067ea2 100644 --- a/core/src/apps/common/seed.py +++ b/core/src/apps/common/seed.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from storage import cache, device from trezor import utils, wire from trezor.crypto import bip32, hmac @@ -5,7 +7,7 @@ from trezor.crypto import bip32, hmac from . import mnemonic from .passphrase import get as get_passphrase -if False: +if TYPE_CHECKING: from .paths import Bip32Path, Slip21Path diff --git a/core/src/apps/common/signverify.py b/core/src/apps/common/signverify.py index 0bfadd3f8..ee0bdb7c2 100644 --- a/core/src/apps/common/signverify.py +++ b/core/src/apps/common/signverify.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor import utils, wire @@ -5,7 +6,7 @@ from trezor.crypto.hashlib import blake256, sha256 from apps.common.writers import write_bitcoin_varint -if False: +if TYPE_CHECKING: from apps.common.coininfo import CoinInfo diff --git a/core/src/apps/common/writers.py b/core/src/apps/common/writers.py index c0f068f99..309d934b1 100644 --- a/core/src/apps/common/writers.py +++ b/core/src/apps/common/writers.py @@ -1,6 +1,8 @@ +from typing import TYPE_CHECKING + from trezor.utils import ensure -if False: +if TYPE_CHECKING: from typing import Union from trezor.utils import Writer diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py index 95ff6b1db..205f735ff 100644 --- a/core/src/apps/debug/__init__.py +++ b/core/src/apps/debug/__init__.py @@ -16,7 +16,9 @@ if __debug__: from apps import workflow_handlers - if False: + from typing import TYPE_CHECKING + + if TYPE_CHECKING: from trezor.ui import Layout from trezor.messages import ( DebugLinkDecision, diff --git a/core/src/apps/debug/load_device.py b/core/src/apps/debug/load_device.py index 1d4330f4c..4f1cfc9f2 100644 --- a/core/src/apps/debug/load_device.py +++ b/core/src/apps/debug/load_device.py @@ -3,13 +3,13 @@ import storage.device from trezor import config, wire from trezor.crypto import bip39, slip39 from trezor.enums import BackupType -from trezor.messages import Success +from trezor.messages import LoadDevice, Success from trezor.ui.layouts import confirm_action from apps.management import backup_types -async def load_device(ctx, msg): +async def load_device(ctx: wire.Context, msg: LoadDevice) -> Success: word_count = _validate(msg) is_slip39 = backup_types.is_slip39_word_count(word_count) @@ -42,7 +42,7 @@ async def load_device(ctx, msg): needs_backup=msg.needs_backup is True, no_backup=msg.no_backup is True, ) - storage.device.set_passphrase_enabled(msg.passphrase_protection) + storage.device.set_passphrase_enabled(bool(msg.passphrase_protection)) storage.device.set_label(msg.label or "") if msg.pin: config.change_pin("", msg.pin, None, None) @@ -50,7 +50,7 @@ async def load_device(ctx, msg): return Success(message="Device loaded") -def _validate(msg) -> int: +def _validate(msg: LoadDevice) -> int: if storage.device.is_initialized(): raise wire.UnexpectedMessage("Already initialized") @@ -67,7 +67,7 @@ def _validate(msg) -> int: return word_count -async def _warn(ctx: wire.Context): +async def _warn(ctx: wire.Context) -> None: await confirm_action( ctx, "warn_loading_seed", diff --git a/core/src/apps/eos/actions/__init__.py b/core/src/apps/eos/actions/__init__.py index 6c377693a..edfe79208 100644 --- a/core/src/apps/eos/actions/__init__.py +++ b/core/src/apps/eos/actions/__init__.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto.hashlib import sha256 from trezor.messages import EosTxActionAck, EosTxActionRequest from trezor.utils import HashWriter @@ -5,7 +7,7 @@ from trezor.utils import HashWriter from .. import helpers, writers from . import layout -if False: +if TYPE_CHECKING: from trezor import wire from trezor.utils import Writer @@ -22,44 +24,57 @@ async def process_action( w = bytearray() if account == "eosio": if name == "buyram": + assert action.buy_ram is not None # check_action await layout.confirm_action_buyram(ctx, action.buy_ram) writers.write_action_buyram(w, action.buy_ram) elif name == "buyrambytes": + assert action.buy_ram_bytes is not None # check_action await layout.confirm_action_buyrambytes(ctx, action.buy_ram_bytes) writers.write_action_buyrambytes(w, action.buy_ram_bytes) elif name == "sellram": + assert action.sell_ram is not None # check_action await layout.confirm_action_sellram(ctx, action.sell_ram) writers.write_action_sellram(w, action.sell_ram) elif name == "delegatebw": + assert action.delegate is not None # check_action await layout.confirm_action_delegate(ctx, action.delegate) writers.write_action_delegate(w, action.delegate) elif name == "undelegatebw": + assert action.undelegate is not None # check_action await layout.confirm_action_undelegate(ctx, action.undelegate) writers.write_action_undelegate(w, action.undelegate) elif name == "refund": + assert action.refund is not None # check_action await layout.confirm_action_refund(ctx, action.refund) writers.write_action_refund(w, action.refund) elif name == "voteproducer": + assert action.vote_producer is not None # check_action await layout.confirm_action_voteproducer(ctx, action.vote_producer) writers.write_action_voteproducer(w, action.vote_producer) elif name == "updateauth": + assert action.update_auth is not None # check_action await layout.confirm_action_updateauth(ctx, action.update_auth) writers.write_action_updateauth(w, action.update_auth) elif name == "deleteauth": + assert action.delete_auth is not None # check_action await layout.confirm_action_deleteauth(ctx, action.delete_auth) writers.write_action_deleteauth(w, action.delete_auth) elif name == "linkauth": + assert action.link_auth is not None # check_action await layout.confirm_action_linkauth(ctx, action.link_auth) writers.write_action_linkauth(w, action.link_auth) elif name == "unlinkauth": + assert action.unlink_auth is not None # check_action await layout.confirm_action_unlinkauth(ctx, action.unlink_auth) writers.write_action_unlinkauth(w, action.unlink_auth) elif name == "newaccount": + assert action.new_account is not None # check_action await layout.confirm_action_newaccount(ctx, action.new_account) writers.write_action_newaccount(w, action.new_account) else: raise ValueError("Unrecognized action type for eosio") elif name == "transfer": + assert action.transfer is not None # check_action await layout.confirm_action_transfer(ctx, action.transfer, account) writers.write_action_transfer(w, action.transfer) else: @@ -72,6 +87,7 @@ async def process_action( async def process_unknown_action( ctx: wire.Context, w: Writer, action: EosTxActionAck ) -> None: + assert action.unknown is not None checksum = HashWriter(sha256()) writers.write_uvarint(checksum, action.unknown.data_size) checksum.extend(action.unknown.data_chunk) diff --git a/core/src/apps/eos/actions/layout.py b/core/src/apps/eos/actions/layout.py index 6ea62cc58..4526ac5c7 100644 --- a/core/src/apps/eos/actions/layout.py +++ b/core/src/apps/eos/actions/layout.py @@ -1,11 +1,12 @@ -from trezor import ui +from typing import TYPE_CHECKING + +from trezor import ui, wire from trezor.enums import ButtonRequestType from trezor.ui.layouts import confirm_properties from .. import helpers -if False: - from trezor import wire +if TYPE_CHECKING: from trezor.messages import ( EosActionBuyRam, EosActionBuyRamBytes, @@ -23,6 +24,7 @@ if False: EosActionVoteProducer, EosAuthorization, ) + from trezor.ui.layouts import PropertyType async def confirm_action_buyram(ctx: wire.Context, msg: EosActionBuyRam) -> None: @@ -194,7 +196,7 @@ async def confirm_action_transfer( async def confirm_action_updateauth( ctx: wire.Context, msg: EosActionUpdateAuth ) -> None: - props = [ + props: list[PropertyType] = [ ("Account:", helpers.eos_name_to_string(msg.account)), ("Permission:", helpers.eos_name_to_string(msg.permission)), ("Parent:", helpers.eos_name_to_string(msg.parent)), @@ -262,7 +264,7 @@ async def confirm_action_unlinkauth( async def confirm_action_newaccount( ctx: wire.Context, msg: EosActionNewAccount ) -> None: - props = [ + props: list[PropertyType] = [ ("Creator:", helpers.eos_name_to_string(msg.creator)), ("Name:", helpers.eos_name_to_string(msg.name)), ] @@ -296,11 +298,14 @@ async def confirm_action_unknown( ) -def authorization_fields(auth: EosAuthorization) -> list[tuple[str, str | None]]: - fields = [] +def authorization_fields(auth: EosAuthorization) -> list[PropertyType]: + fields: list[PropertyType] = [] fields.append(("Threshold:", str(auth.threshold))) for i, key in enumerate(auth.keys, 1): + if key.key is None: + raise wire.DataError("Key must be provided explicitly.") + _key = helpers.public_key_to_wif(bytes(key.key)) _weight = str(key.weight) diff --git a/core/src/apps/eos/get_public_key.py b/core/src/apps/eos/get_public_key.py index efb793c62..75d3776d3 100644 --- a/core/src/apps/eos/get_public_key.py +++ b/core/src/apps/eos/get_public_key.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import secp256k1 from trezor.messages import EosGetPublicKey, EosPublicKey @@ -8,7 +10,7 @@ from apps.common.keychain import Keychain, auto_keychain from .helpers import public_key_to_wif from .layout import require_get_public_key -if False: +if TYPE_CHECKING: from trezor.crypto import bip32 diff --git a/core/src/apps/eos/sign_tx.py b/core/src/apps/eos/sign_tx.py index 05fc38f86..9070acad8 100644 --- a/core/src/apps/eos/sign_tx.py +++ b/core/src/apps/eos/sign_tx.py @@ -15,11 +15,7 @@ from .layout import require_sign_tx @auto_keychain(__name__) async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx: - if msg.chain_id is None: - raise wire.DataError("No chain id") - if msg.header is None: - raise wire.DataError("No header") - if msg.num_actions is None or msg.num_actions == 0: + if not msg.num_actions: raise wire.DataError("No actions") await paths.validate_path(ctx, keychain, msg.address_n) diff --git a/core/src/apps/eos/writers.py b/core/src/apps/eos/writers.py index bec0d4727..d23c52cb9 100644 --- a/core/src/apps/eos/writers.py +++ b/core/src/apps/eos/writers.py @@ -1,3 +1,7 @@ +from typing import TYPE_CHECKING + +from trezor import wire + from apps.common.writers import ( write_bytes_fixed, write_bytes_unchecked, @@ -8,7 +12,7 @@ from apps.common.writers import ( write_uvarint, ) -if False: +if TYPE_CHECKING: from trezor.messages import ( EosActionBuyRam, EosActionBuyRamBytes, @@ -16,6 +20,7 @@ if False: EosActionDelegate, EosActionDeleteAuth, EosActionLinkAuth, + EosActionUnlinkAuth, EosActionNewAccount, EosActionRefund, EosActionSellRam, @@ -34,6 +39,8 @@ def write_auth(w: Writer, auth: EosAuthorization) -> None: write_uint32_le(w, auth.threshold) write_uvarint(w, len(auth.keys)) for key in auth.keys: + if key.key is None: + raise wire.DataError("Key must be provided explicitly.") write_uvarint(w, key.type) write_bytes_fixed(w, key.key, 33) write_uint16_le(w, key.weight) @@ -63,7 +70,7 @@ def write_action_transfer(w: Writer, msg: EosActionTransfer) -> None: write_uint64_le(w, msg.sender) write_uint64_le(w, msg.receiver) write_asset(w, msg.quantity) - write_bytes_prefixed(w, msg.memo) + write_bytes_prefixed(w, msg.memo.encode()) def write_action_buyram(w: Writer, msg: EosActionBuyRam) -> None: @@ -129,7 +136,7 @@ def write_action_linkauth(w: Writer, msg: EosActionLinkAuth) -> None: write_uint64_le(w, msg.requirement) -def write_action_unlinkauth(w: Writer, msg: EosActionLinkAuth) -> None: +def write_action_unlinkauth(w: Writer, msg: EosActionUnlinkAuth) -> None: write_uint64_le(w, msg.account) write_uint64_le(w, msg.code) write_uint64_le(w, msg.type) diff --git a/core/src/apps/ethereum/get_address.py b/core/src/apps/ethereum/get_address.py index c2fe8eac6..7fbb37794 100644 --- a/core/src/apps/ethereum/get_address.py +++ b/core/src/apps/ethereum/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import EthereumAddress from trezor.ui.layouts import show_address @@ -7,7 +9,7 @@ from . import networks from .helpers import address_from_bytes from .keychain import PATTERNS_ADDRESS, with_keychain_from_path -if False: +if TYPE_CHECKING: from trezor.messages import EthereumGetAddress from trezor.wire import Context diff --git a/core/src/apps/ethereum/get_public_key.py b/core/src/apps/ethereum/get_public_key.py index b62110e7f..beadd8875 100644 --- a/core/src/apps/ethereum/get_public_key.py +++ b/core/src/apps/ethereum/get_public_key.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor.messages import EthereumPublicKey, HDNodeType @@ -7,7 +8,7 @@ from apps.common import coins, paths from .keychain import with_keychain_from_path -if False: +if TYPE_CHECKING: from trezor.messages import EthereumGetPublicKey from trezor.wire import Context diff --git a/core/src/apps/ethereum/helpers.py b/core/src/apps/ethereum/helpers.py index 226062014..de53c7147 100644 --- a/core/src/apps/ethereum/helpers.py +++ b/core/src/apps/ethereum/helpers.py @@ -1,10 +1,11 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify, unhexlify from trezor import wire from trezor.enums import EthereumDataType from trezor.messages import EthereumFieldType -if False: +if TYPE_CHECKING: from .networks import NetworkInfo diff --git a/core/src/apps/ethereum/keychain.py b/core/src/apps/ethereum/keychain.py index b151f5895..137a81a6d 100644 --- a/core/src/apps/ethereum/keychain.py +++ b/core/src/apps/ethereum/keychain.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from apps.common import paths @@ -5,7 +7,7 @@ from apps.common.keychain import get_keychain from . import CURVE, networks -if False: +if TYPE_CHECKING: from typing import Callable, Iterable, TypeVar, Union from trezor.messages import ( diff --git a/core/src/apps/ethereum/layout.py b/core/src/apps/ethereum/layout.py index 6ef256064..6bcf80f14 100644 --- a/core/src/apps/ethereum/layout.py +++ b/core/src/apps/ethereum/layout.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor import ui @@ -17,8 +18,9 @@ from trezor.ui.layouts.tt.altcoin import confirm_total_ethereum from . import networks, tokens from .helpers import address_from_bytes, decode_typed_data, get_type_name -if False: +if TYPE_CHECKING: from typing import Awaitable, Iterable, Optional + from trezor.wire import Context diff --git a/core/src/apps/ethereum/networks.py b/core/src/apps/ethereum/networks.py index 3131a320a..6938cbc0c 100644 --- a/core/src/apps/ethereum/networks.py +++ b/core/src/apps/ethereum/networks.py @@ -1,11 +1,9 @@ # generated from networks.py.mako # do not edit manually! +from typing import Iterator from apps.common.paths import HARDENED -if False: - from typing import Iterator - def shortcut_by_chain_id(chain_id: int) -> str: n = by_chain_id(chain_id) diff --git a/core/src/apps/ethereum/networks.py.mako b/core/src/apps/ethereum/networks.py.mako index 56bfef680..c644ce89e 100644 --- a/core/src/apps/ethereum/networks.py.mako +++ b/core/src/apps/ethereum/networks.py.mako @@ -1,11 +1,9 @@ # generated from networks.py.mako # do not edit manually! +from typing import Iterator from apps.common.paths import HARDENED -if False: - from typing import Iterator - def shortcut_by_chain_id(chain_id: int) -> str: n = by_chain_id(chain_id) diff --git a/core/src/apps/ethereum/sign_message.py b/core/src/apps/ethereum/sign_message.py index 84218546a..3a5a5dd5d 100644 --- a/core/src/apps/ethereum/sign_message.py +++ b/core/src/apps/ethereum/sign_message.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto.curve import secp256k1 from trezor.crypto.hashlib import sha3_256 from trezor.messages import EthereumMessageSignature @@ -10,7 +12,7 @@ from apps.common.signverify import decode_message from .helpers import address_from_bytes from .keychain import PATTERNS_ADDRESS, with_keychain_from_path -if False: +if TYPE_CHECKING: from trezor.messages import EthereumSignMessage from trezor.wire import Context diff --git a/core/src/apps/ethereum/sign_tx.py b/core/src/apps/ethereum/sign_tx.py index 45ab1e914..af002920b 100644 --- a/core/src/apps/ethereum/sign_tx.py +++ b/core/src/apps/ethereum/sign_tx.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto import rlp from trezor.crypto.curve import secp256k1 @@ -17,7 +19,7 @@ from .layout import ( require_confirm_unknown_token, ) -if False: +if TYPE_CHECKING: from typing import Tuple from apps.common.keychain import Keychain diff --git a/core/src/apps/ethereum/sign_tx_eip1559.py b/core/src/apps/ethereum/sign_tx_eip1559.py index 489b12cc3..71e4e84db 100644 --- a/core/src/apps/ethereum/sign_tx_eip1559.py +++ b/core/src/apps/ethereum/sign_tx_eip1559.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto import rlp from trezor.crypto.curve import secp256k1 @@ -16,7 +18,7 @@ from .layout import ( ) from .sign_tx import check_common_fields, handle_erc20, send_request_chunk -if False: +if TYPE_CHECKING: from typing import Tuple from trezor.messages import EthereumSignTxEIP1559 diff --git a/core/src/apps/ethereum/sign_typed_data.py b/core/src/apps/ethereum/sign_typed_data.py index a0ed12f0a..d423068c8 100644 --- a/core/src/apps/ethereum/sign_typed_data.py +++ b/core/src/apps/ethereum/sign_typed_data.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import secp256k1 from trezor.crypto.hashlib import sha3_256 @@ -25,7 +27,7 @@ from .layout import ( should_show_struct, ) -if False: +if TYPE_CHECKING: from apps.common.keychain import Keychain from trezor.wire import Context diff --git a/core/src/apps/ethereum/verify_message.py b/core/src/apps/ethereum/verify_message.py index a04bb349a..eac48fa72 100644 --- a/core/src/apps/ethereum/verify_message.py +++ b/core/src/apps/ethereum/verify_message.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import secp256k1 from trezor.crypto.hashlib import sha3_256 @@ -9,7 +11,7 @@ from apps.common.signverify import decode_message from .helpers import address_from_bytes, bytes_from_address from .sign_message import message_digest -if False: +if TYPE_CHECKING: from trezor.messages import EthereumVerifyMessage from trezor.wire import Context diff --git a/core/src/apps/homescreen/__init__.py b/core/src/apps/homescreen/__init__.py index 2d30a0bd5..07384537e 100644 --- a/core/src/apps/homescreen/__init__.py +++ b/core/src/apps/homescreen/__init__.py @@ -1,3 +1,5 @@ +from typing import Any + import storage.cache import storage.device from trezor import res, ui @@ -16,7 +18,7 @@ class HomescreenBase(ui.Layout): "apps/homescreen/res/bg.toif" ) - async def __iter__(self) -> ui.ResultValue: + async def __iter__(self) -> Any: # We need to catch the ui.Cancelled exception that kills us, because that means # that we will need to draw on screen again after restart. try: diff --git a/core/src/apps/management/apply_flags.py b/core/src/apps/management/apply_flags.py index ab502d4a9..04f7c65bb 100644 --- a/core/src/apps/management/apply_flags.py +++ b/core/src/apps/management/apply_flags.py @@ -1,9 +1,11 @@ +from typing import TYPE_CHECKING + import storage.device from storage.device import set_flags from trezor import wire from trezor.messages import Success -if False: +if TYPE_CHECKING: from trezor.messages import ApplyFlags diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py index d16d0021d..438d70fa1 100644 --- a/core/src/apps/management/apply_settings.py +++ b/core/src/apps/management/apply_settings.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage.device from trezor import ui, wire from trezor.enums import ButtonRequestType, SafetyCheckLevel @@ -8,7 +10,7 @@ from trezor.ui.layouts import confirm_action from apps.base import reload_settings_from_storage from apps.common import safety_checks -if False: +if TYPE_CHECKING: from trezor.messages import ApplySettings diff --git a/core/src/apps/management/backup_device.py b/core/src/apps/management/backup_device.py index b278c8843..671568484 100644 --- a/core/src/apps/management/backup_device.py +++ b/core/src/apps/management/backup_device.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage import storage.device from trezor import wire @@ -7,7 +9,7 @@ from apps.common import mnemonic from .reset_device import backup_seed, layout -if False: +if TYPE_CHECKING: from trezor.messages import BackupDevice diff --git a/core/src/apps/management/change_pin.py b/core/src/apps/management/change_pin.py index 1eb9df64e..a94760803 100644 --- a/core/src/apps/management/change_pin.py +++ b/core/src/apps/management/change_pin.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from storage.device import is_initialized from trezor import config, wire from trezor.messages import Success @@ -10,7 +12,7 @@ from apps.common.request_pin import ( request_pin_confirm, ) -if False: +if TYPE_CHECKING: from typing import Awaitable from trezor.messages import ChangePin diff --git a/core/src/apps/management/change_wipe_code.py b/core/src/apps/management/change_wipe_code.py index 245018a49..b9e5ecbcb 100644 --- a/core/src/apps/management/change_wipe_code.py +++ b/core/src/apps/management/change_wipe_code.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from storage.device import is_initialized from trezor import config, ui, wire from trezor.messages import Success @@ -9,7 +11,7 @@ from apps.common.request_pin import ( request_pin_and_sd_salt, ) -if False: +if TYPE_CHECKING: from typing import Awaitable from trezor.messages import ChangeWipeCode diff --git a/core/src/apps/management/recovery_device/__init__.py b/core/src/apps/management/recovery_device/__init__.py index ce63b3701..5c55e9942 100644 --- a/core/src/apps/management/recovery_device/__init__.py +++ b/core/src/apps/management/recovery_device/__init__.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage import storage.device import storage.recovery @@ -14,7 +16,7 @@ from apps.common.request_pin import ( from .homescreen import recovery_homescreen, recovery_process -if False: +if TYPE_CHECKING: from trezor.messages import RecoveryDevice diff --git a/core/src/apps/management/recovery_device/layout.py b/core/src/apps/management/recovery_device/layout.py index 08e7484d1..335b0903f 100644 --- a/core/src/apps/management/recovery_device/layout.py +++ b/core/src/apps/management/recovery_device/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage.recovery from trezor import ui, wire from trezor.enums import ButtonRequestType @@ -15,7 +17,7 @@ from .. import backup_types from . import word_validity from .recover import RecoveryAborted -if False: +if TYPE_CHECKING: from typing import Callable from trezor.enums import BackupType diff --git a/core/src/apps/management/recovery_device/recover.py b/core/src/apps/management/recovery_device/recover.py index 8643db083..22398b459 100644 --- a/core/src/apps/management/recovery_device/recover.py +++ b/core/src/apps/management/recovery_device/recover.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage.recovery import storage.recovery_shares from trezor.crypto import bip39, slip39 @@ -5,7 +7,7 @@ from trezor.errors import MnemonicError from .. import backup_types -if False: +if TYPE_CHECKING: from trezor.enums import BackupType from typing import Union @@ -91,7 +93,7 @@ def process_slip39(words: str) -> tuple[bytes | None, slip39.Share]: return secret, share -if False: +if TYPE_CHECKING: Slip39State = Union[tuple[int, BackupType], tuple[None, None]] diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 547fd6927..adbd808b5 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage import storage.device from trezor import config, wire @@ -14,7 +16,7 @@ from . import layout if __debug__: import storage.debug -if False: +if TYPE_CHECKING: from trezor.messages import ResetDevice _DEFAULT_BACKUP_TYPE = BackupType.Bip39 diff --git a/core/src/apps/management/reset_device/layout.py b/core/src/apps/management/reset_device/layout.py index 68aa8ac3c..0ff39e87d 100644 --- a/core/src/apps/management/reset_device/layout.py +++ b/core/src/apps/management/reset_device/layout.py @@ -1,3 +1,5 @@ +from typing import Sequence + from trezor import ui, utils, wire from trezor.enums import ButtonRequestType from trezor.ui.layouts import confirm_action, confirm_blob, show_success, show_warning @@ -11,9 +13,6 @@ from trezor.ui.layouts.tt.reset import ( # noqa: F401 slip39_show_checklist, ) -if False: - from typing import Sequence - async def show_internal_entropy(ctx: wire.GenericContext, entropy: bytes) -> None: await confirm_blob( diff --git a/core/src/apps/management/sd_protect.py b/core/src/apps/management/sd_protect.py index 111136c10..267d2b99f 100644 --- a/core/src/apps/management/sd_protect.py +++ b/core/src/apps/management/sd_protect.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage.device import storage.sd_salt from trezor import config, wire @@ -13,7 +15,7 @@ from apps.common.request_pin import ( ) from apps.common.sdcard import confirm_retry_sd, ensure_sdcard -if False: +if TYPE_CHECKING: from typing import Awaitable from trezor.messages import SdProtect diff --git a/core/src/apps/management/wipe_device.py b/core/src/apps/management/wipe_device.py index 577820961..9ad4f633f 100644 --- a/core/src/apps/management/wipe_device.py +++ b/core/src/apps/management/wipe_device.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import storage from trezor import ui from trezor.enums import ButtonRequestType @@ -6,7 +8,7 @@ from trezor.ui.layouts import confirm_action from .apply_settings import reload_settings_from_storage -if False: +if TYPE_CHECKING: from trezor import wire from trezor.messages import WipeDevice diff --git a/core/src/apps/misc/cipher_key_value.py b/core/src/apps/misc/cipher_key_value.py index 343065413..6d3d07fce 100644 --- a/core/src/apps/misc/cipher_key_value.py +++ b/core/src/apps/misc/cipher_key_value.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto import aes, hmac from trezor.messages import CipheredKeyValue @@ -6,16 +8,14 @@ from trezor.ui.layouts import confirm_action from apps.common.keychain import get_keychain from apps.common.paths import AlwaysMatchingSchema -if False: - from trezor.wire import Context - +if TYPE_CHECKING: from trezor.messages import CipherKeyValue # This module implements the SLIP-0011 symmetric encryption of key-value pairs using a # deterministic hierarchy, see https://github.com/satoshilabs/slips/blob/master/slip-0011.md. -async def cipher_key_value(ctx: Context, msg: CipherKeyValue) -> CipheredKeyValue: +async def cipher_key_value(ctx: wire.Context, msg: CipherKeyValue) -> CipheredKeyValue: keychain = await get_keychain(ctx, "secp256k1", [AlwaysMatchingSchema]) if len(msg.value) % 16 > 0: diff --git a/core/src/apps/misc/get_ecdh_session_key.py b/core/src/apps/misc/get_ecdh_session_key.py index f4e16bbb1..065b2285e 100644 --- a/core/src/apps/misc/get_ecdh_session_key.py +++ b/core/src/apps/misc/get_ecdh_session_key.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ustruct import pack, unpack from trezor import ui, wire @@ -10,7 +11,7 @@ from apps.common.paths import HARDENED, AlwaysMatchingSchema from .sign_identity import serialize_identity, serialize_identity_without_proto -if False: +if TYPE_CHECKING: from trezor.messages import GetECDHSessionKey, IdentityType from apps.common.paths import Bip32Path diff --git a/core/src/apps/misc/get_entropy.py b/core/src/apps/misc/get_entropy.py index b8876fda3..62a1114dc 100644 --- a/core/src/apps/misc/get_entropy.py +++ b/core/src/apps/misc/get_entropy.py @@ -1,9 +1,11 @@ +from typing import TYPE_CHECKING + from trezor.crypto import random from trezor.enums import ButtonRequestType from trezor.messages import Entropy from trezor.ui.layouts import confirm_action -if False: +if TYPE_CHECKING: from trezor.wire import Context from trezor.messages import GetEntropy diff --git a/core/src/apps/misc/sign_identity.py b/core/src/apps/misc/sign_identity.py index 7e2e4247a..816af0128 100644 --- a/core/src/apps/misc/sign_identity.py +++ b/core/src/apps/misc/sign_identity.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ustruct import pack, unpack from trezor import wire @@ -9,7 +10,7 @@ from apps.common import coininfo from apps.common.keychain import get_keychain from apps.common.paths import HARDENED, AlwaysMatchingSchema -if False: +if TYPE_CHECKING: from trezor.messages import IdentityType, SignIdentity from apps.common.paths import Bip32Path @@ -124,12 +125,6 @@ def sign_challenge( sigtype: str | coininfo.CoinInfo, curve: str, ) -> bytes: - if curve == "secp256k1": - from trezor.crypto.curve import secp256k1 - elif curve == "nist256p1": - from trezor.crypto.curve import nist256p1 - elif curve == "ed25519": - from trezor.crypto.curve import ed25519 from apps.common.signverify import message_digest if sigtype == "gpg": @@ -154,10 +149,16 @@ def sign_challenge( raise wire.DataError("Unsupported sigtype") if curve == "secp256k1": + from trezor.crypto.curve import secp256k1 + signature = secp256k1.sign(seckey, data) elif curve == "nist256p1": + from trezor.crypto.curve import nist256p1 + signature = nist256p1.sign(seckey, data) elif curve == "ed25519": + from trezor.crypto.curve import ed25519 + signature = ed25519.sign(seckey, data) else: raise wire.DataError("Unknown curve") diff --git a/core/src/apps/monero/layout.py b/core/src/apps/monero/layout.py index 29e31cbc6..e2b2ec2e8 100644 --- a/core/src/apps/monero/layout.py +++ b/core/src/apps/monero/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import strings, ui from trezor.enums import ButtonRequestType from trezor.ui.layouts import ( @@ -11,7 +13,7 @@ from trezor.ui.popup import Popup DUMMY_PAYMENT_ID = b"\x00\x00\x00\x00\x00\x00\x00\x00" -if False: +if TYPE_CHECKING: from apps.monero.signing.state import State from trezor.messages import ( MoneroTransactionData, diff --git a/core/src/apps/monero/misc.py b/core/src/apps/monero/misc.py index 7712a75da..883e6a99d 100644 --- a/core/src/apps/monero/misc.py +++ b/core/src/apps/monero/misc.py @@ -1,4 +1,6 @@ -if False: +from typing import TYPE_CHECKING + +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519 diff --git a/core/src/apps/monero/signing/offloading_keys.py b/core/src/apps/monero/signing/offloading_keys.py index 4101c4752..10e5fd991 100644 --- a/core/src/apps/monero/signing/offloading_keys.py +++ b/core/src/apps/monero/signing/offloading_keys.py @@ -1,10 +1,11 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import utils from apps.monero.xmr import crypto -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519 from trezor.messages import ( MoneroTransactionDestinationEntry, diff --git a/core/src/apps/monero/signing/state.py b/core/src/apps/monero/signing/state.py index d0553790d..23f4aea3a 100644 --- a/core/src/apps/monero/signing/state.py +++ b/core/src/apps/monero/signing/state.py @@ -1,11 +1,12 @@ import gc from micropython import const +from typing import TYPE_CHECKING from trezor import log from apps.monero.xmr import crypto -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Ge25519, Sc25519 from apps.monero.xmr.credentials import AccountCreds diff --git a/core/src/apps/monero/signing/step_01_init_transaction.py b/core/src/apps/monero/signing/step_01_init_transaction.py index 445c31970..9cbc645a8 100644 --- a/core/src/apps/monero/signing/step_01_init_transaction.py +++ b/core/src/apps/monero/signing/step_01_init_transaction.py @@ -3,12 +3,13 @@ Initializes a new transaction. """ import gc +from typing import TYPE_CHECKING from apps.monero import layout, misc, signing from apps.monero.signing.state import State from apps.monero.xmr import crypto, monero -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519, Ge25519 from trezor.messages import ( MoneroAccountPublicAddress, diff --git a/core/src/apps/monero/signing/step_02_set_input.py b/core/src/apps/monero/signing/step_02_set_input.py index d46b0736f..5a1d5b05e 100644 --- a/core/src/apps/monero/signing/step_02_set_input.py +++ b/core/src/apps/monero/signing/step_02_set_input.py @@ -11,12 +11,14 @@ If number of inputs is small, in-memory mode is used = alpha, pseudo_outs are ke Otherwise pseudo_outs are offloaded with HMAC, alpha is offloaded encrypted under chacha_poly with key derived for exactly this purpose. """ +from typing import TYPE_CHECKING + from apps.monero import layout from apps.monero.xmr import crypto, monero, serialize from .state import State -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519, Ge25519 from trezor.messages import MoneroTransactionSourceEntry from trezor.messages import MoneroTransactionSetInputAck diff --git a/core/src/apps/monero/signing/step_03_inputs_permutation.py b/core/src/apps/monero/signing/step_03_inputs_permutation.py index e1d36199f..5628386cb 100644 --- a/core/src/apps/monero/signing/step_03_inputs_permutation.py +++ b/core/src/apps/monero/signing/step_03_inputs_permutation.py @@ -16,11 +16,13 @@ HMAC correctness (host sends original sort idx) and ordering check on the key images. This step is skipped. """ +from typing import TYPE_CHECKING + from apps.monero.layout import transaction_step from .state import State -if False: +if TYPE_CHECKING: from trezor.messages import MoneroTransactionInputsPermutationAck diff --git a/core/src/apps/monero/signing/step_04_input_vini.py b/core/src/apps/monero/signing/step_04_input_vini.py index b177d6c04..71d759ae7 100644 --- a/core/src/apps/monero/signing/step_04_input_vini.py +++ b/core/src/apps/monero/signing/step_04_input_vini.py @@ -3,13 +3,15 @@ This step serves for an incremental hashing of tx.vin[i] to the tx_prefix_hasher after the sorting on tx.vin[i].ki. The sorting order was received in the previous step. """ +from typing import TYPE_CHECKING + from apps.monero import layout from apps.monero.signing import offloading_keys from apps.monero.xmr import crypto from .state import State -if False: +if TYPE_CHECKING: from trezor.messages import ( MoneroTransactionInputViniAck, MoneroTransactionSourceEntry, diff --git a/core/src/apps/monero/signing/step_05_all_inputs_set.py b/core/src/apps/monero/signing/step_05_all_inputs_set.py index 936b70c44..b35dae446 100644 --- a/core/src/apps/monero/signing/step_05_all_inputs_set.py +++ b/core/src/apps/monero/signing/step_05_all_inputs_set.py @@ -3,12 +3,14 @@ All inputs set. Defining range signature parameters. If in the applicable offloading mode, generate commitment masks. """ +from typing import TYPE_CHECKING + from apps.monero import layout from apps.monero.xmr import crypto from .state import State -if False: +if TYPE_CHECKING: from trezor.messages import MoneroTransactionAllInputsSetAck diff --git a/core/src/apps/monero/signing/step_06_set_output.py b/core/src/apps/monero/signing/step_06_set_output.py index bf85a50d7..c6d30758a 100644 --- a/core/src/apps/monero/signing/step_06_set_output.py +++ b/core/src/apps/monero/signing/step_06_set_output.py @@ -3,6 +3,7 @@ Output destinations are streamed one by one. Computes destination one-time address, amount key, range proof + HMAC, out_pk, ecdh_info. """ import gc +from typing import TYPE_CHECKING from trezor import utils @@ -12,7 +13,7 @@ from apps.monero.xmr import crypto, serialize from .state import State -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519, Ge25519 from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof diff --git a/core/src/apps/monero/signing/step_07_all_outputs_set.py b/core/src/apps/monero/signing/step_07_all_outputs_set.py index adaaf5046..7f958ce91 100644 --- a/core/src/apps/monero/signing/step_07_all_outputs_set.py +++ b/core/src/apps/monero/signing/step_07_all_outputs_set.py @@ -5,6 +5,7 @@ The prefix hash is then complete. """ import gc +from typing import TYPE_CHECKING from trezor import utils @@ -13,7 +14,7 @@ from apps.monero.xmr import crypto from .state import State -if False: +if TYPE_CHECKING: from trezor.messages import MoneroTransactionAllOutSetAck diff --git a/core/src/apps/monero/signing/step_09_sign_input.py b/core/src/apps/monero/signing/step_09_sign_input.py index 8bb3c8646..4cec187e8 100644 --- a/core/src/apps/monero/signing/step_09_sign_input.py +++ b/core/src/apps/monero/signing/step_09_sign_input.py @@ -11,6 +11,7 @@ on output masks as pseudo outputs have to remain same. """ import gc +from typing import TYPE_CHECKING from trezor import utils @@ -19,7 +20,7 @@ from apps.monero.xmr import crypto from .state import State -if False: +if TYPE_CHECKING: from trezor.messages import MoneroTransactionSourceEntry from trezor.messages import MoneroTransactionSignInputAck diff --git a/core/src/apps/monero/signing/step_10_sign_final.py b/core/src/apps/monero/signing/step_10_sign_final.py index cdcb9dcec..f211fd06c 100644 --- a/core/src/apps/monero/signing/step_10_sign_final.py +++ b/core/src/apps/monero/signing/step_10_sign_final.py @@ -8,6 +8,8 @@ so we can recover it just from the transaction and the spend key. The private tx keys are used in other numerous Monero features. """ +from typing import TYPE_CHECKING + from trezor.messages import MoneroTransactionFinalAck from apps.monero import misc @@ -16,7 +18,7 @@ from apps.monero.xmr.crypto import chacha_poly from .state import State -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519 diff --git a/core/src/apps/monero/xmr/addresses.py b/core/src/apps/monero/xmr/addresses.py index a6c5a9579..4adfe6b4f 100644 --- a/core/src/apps/monero/xmr/addresses.py +++ b/core/src/apps/monero/xmr/addresses.py @@ -1,8 +1,10 @@ +from typing import TYPE_CHECKING + from trezor.crypto import monero as tcry from apps.monero.xmr.networks import NetworkTypes, net_version -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Ge25519 from trezor.messages import MoneroAccountPublicAddress from trezor.messages import MoneroTransactionDestinationEntry diff --git a/core/src/apps/monero/xmr/credentials.py b/core/src/apps/monero/xmr/credentials.py index 90a1844fd..e78fc9821 100644 --- a/core/src/apps/monero/xmr/credentials.py +++ b/core/src/apps/monero/xmr/credentials.py @@ -1,8 +1,10 @@ +from typing import TYPE_CHECKING + from apps.monero.xmr import crypto from apps.monero.xmr.addresses import encode_addr from apps.monero.xmr.networks import NetworkTypes, net_version -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519, Ge25519 diff --git a/core/src/apps/monero/xmr/crypto/__init__.py b/core/src/apps/monero/xmr/crypto/__init__.py index 640dcb481..a9d0a846d 100644 --- a/core/src/apps/monero/xmr/crypto/__init__.py +++ b/core/src/apps/monero/xmr/crypto/__init__.py @@ -7,10 +7,12 @@ # https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-00#section-4 # https://github.com/monero-project/research-lab +from typing import TYPE_CHECKING + from trezor.crypto import monero as tcry, random from trezor.crypto.hashlib import sha3_256 -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519, Ge25519 diff --git a/core/src/apps/monero/xmr/key_image.py b/core/src/apps/monero/xmr/key_image.py index b3a254729..26c4cf092 100644 --- a/core/src/apps/monero/xmr/key_image.py +++ b/core/src/apps/monero/xmr/key_image.py @@ -1,7 +1,9 @@ +from typing import TYPE_CHECKING + from apps.monero.xmr import crypto, monero from apps.monero.xmr.serialize.int_serialize import dump_uvarint_b -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Ge25519, Sc25519 from apps.monero.xmr.credentials import AccountCreds from trezor.messages import MoneroTransferDetails diff --git a/core/src/apps/monero/xmr/mlsag.py b/core/src/apps/monero/xmr/mlsag.py index f81203775..6b5ec1c5f 100644 --- a/core/src/apps/monero/xmr/mlsag.py +++ b/core/src/apps/monero/xmr/mlsag.py @@ -43,11 +43,12 @@ Author: Dusan Klinec, ph4r05, 2018 """ import gc +from typing import TYPE_CHECKING from apps.monero.xmr import crypto from apps.monero.xmr.serialize import int_serialize -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Ge25519, Sc25519 from apps.monero.xmr.serialize_messages.tx_ct_key import CtKey from trezor.messages import MoneroRctKeyPublic diff --git a/core/src/apps/monero/xmr/mlsag_hasher.py b/core/src/apps/monero/xmr/mlsag_hasher.py index 7ddfbf565..77cd94c2b 100644 --- a/core/src/apps/monero/xmr/mlsag_hasher.py +++ b/core/src/apps/monero/xmr/mlsag_hasher.py @@ -1,7 +1,9 @@ +from typing import TYPE_CHECKING + from apps.monero.xmr import crypto from apps.monero.xmr.keccak_hasher import KeccakXmrArchive -if False: +if TYPE_CHECKING: from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof diff --git a/core/src/apps/monero/xmr/monero.py b/core/src/apps/monero/xmr/monero.py index 7d646e813..a3d88fb8f 100644 --- a/core/src/apps/monero/xmr/monero.py +++ b/core/src/apps/monero/xmr/monero.py @@ -1,6 +1,8 @@ +from typing import TYPE_CHECKING + from apps.monero.xmr import crypto -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Ge25519, Sc25519 from apps.monero.xmr.credentials import AccountCreds diff --git a/core/src/apps/monero/xmr/range_signatures.py b/core/src/apps/monero/xmr/range_signatures.py index 3362e0703..adb280716 100644 --- a/core/src/apps/monero/xmr/range_signatures.py +++ b/core/src/apps/monero/xmr/range_signatures.py @@ -9,10 +9,11 @@ Author: Dusan Klinec, ph4r05, 2018 """ import gc +from typing import TYPE_CHECKING from apps.monero.xmr import crypto -if False: +if TYPE_CHECKING: from apps.monero.xmr.types import Sc25519 from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import Bulletproof diff --git a/core/src/apps/monero/xmr/types.py b/core/src/apps/monero/xmr/types.py index 964463d35..60cd6b5e6 100644 --- a/core/src/apps/monero/xmr/types.py +++ b/core/src/apps/monero/xmr/types.py @@ -1,4 +1,6 @@ -if False: +from typing import TYPE_CHECKING + +if TYPE_CHECKING: from trezor.crypto import monero as tcry Ge25519 = tcry.ge25519 diff --git a/core/src/apps/nem/get_address.py b/core/src/apps/nem/get_address.py index 0fc884825..2b14ac9a8 100644 --- a/core/src/apps/nem/get_address.py +++ b/core/src/apps/nem/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMAddress from trezor.ui.layouts import show_address @@ -8,16 +10,23 @@ from . import CURVE, PATTERNS, SLIP44_ID from .helpers import check_path, get_network_str from .validators import validate_network +if TYPE_CHECKING: + from apps.common.keychain import Keychain + from trezor.wire import Context + from trezor.messages import NEMGetAddress + @with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) -async def get_address(ctx, msg, keychain): - network = validate_network(msg.network) +async def get_address( + ctx: Context, msg: NEMGetAddress, keychain: Keychain +) -> NEMAddress: + validate_network(msg.network) await validate_path( ctx, keychain, msg.address_n, check_path(msg.address_n, msg.network) ) node = keychain.derive(msg.address_n) - address = node.nem_address(network) + address = node.nem_address(msg.network) if msg.show_display: title = address_n_to_str(msg.address_n) @@ -26,7 +35,7 @@ async def get_address(ctx, msg, keychain): address=address, address_qr=address.upper(), title=title, - network=get_network_str(network), + network=get_network_str(msg.network), ) return NEMAddress(address=address) diff --git a/core/src/apps/nem/helpers.py b/core/src/apps/nem/helpers.py index 14ffb3eff..609a3480c 100644 --- a/core/src/apps/nem/helpers.py +++ b/core/src/apps/nem/helpers.py @@ -39,7 +39,7 @@ def get_network_str(network: int) -> str: elif network == NEM_NETWORK_MIJIN: return "Mijin" - raise RuntimeError # network should be one of the NEM_NETWORK_* constants + raise ValueError # no valid network def check_path(path: paths.Bip32Path, network: int) -> bool: diff --git a/core/src/apps/nem/layout.py b/core/src/apps/nem/layout.py index b680bd89c..1e93bc849 100644 --- a/core/src/apps/nem/layout.py +++ b/core/src/apps/nem/layout.py @@ -1,11 +1,16 @@ +from typing import TYPE_CHECKING + from trezor.enums import ButtonRequestType from trezor.strings import format_amount from trezor.ui.layouts import confirm_metadata, confirm_properties from .helpers import NEM_MAX_DIVISIBILITY +if TYPE_CHECKING: + from trezor.wire import Context + -async def require_confirm_text(ctx, action: str): +async def require_confirm_text(ctx: Context, action: str) -> None: await confirm_metadata( ctx, "confirm_nem", @@ -16,7 +21,7 @@ async def require_confirm_text(ctx, action: str): ) -async def require_confirm_fee(ctx, action: str, fee: int): +async def require_confirm_fee(ctx: Context, action: str, fee: int) -> None: await confirm_metadata( ctx, "confirm_fee", @@ -28,7 +33,7 @@ async def require_confirm_fee(ctx, action: str, fee: int): ) -async def require_confirm_content(ctx, headline: str, content: list): +async def require_confirm_content(ctx: Context, headline: str, content: list) -> None: await confirm_properties( ctx, "confirm_content", @@ -37,7 +42,7 @@ async def require_confirm_content(ctx, headline: str, content: list): ) -async def require_confirm_final(ctx, fee: int): +async def require_confirm_final(ctx: Context, fee: int) -> None: # we use SignTx, not ConfirmOutput, for compatibility with T1 await confirm_metadata( ctx, diff --git a/core/src/apps/nem/mosaic/__init__.py b/core/src/apps/nem/mosaic/__init__.py index 4190e3a79..216835188 100644 --- a/core/src/apps/nem/mosaic/__init__.py +++ b/core/src/apps/nem/mosaic/__init__.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import ( NEMMosaicCreation, NEMMosaicSupplyChange, @@ -6,16 +8,25 @@ from trezor.messages import ( from . import layout, serialize +if TYPE_CHECKING: + from trezor.wire import Context + async def mosaic_creation( - ctx, public_key: bytes, common: NEMTransactionCommon, creation: NEMMosaicCreation -) -> bytearray: + ctx: Context, + public_key: bytes, + common: NEMTransactionCommon, + creation: NEMMosaicCreation, +) -> bytes: await layout.ask_mosaic_creation(ctx, common, creation) return serialize.serialize_mosaic_creation(common, creation, public_key) async def supply_change( - ctx, public_key: bytes, common: NEMTransactionCommon, change: NEMMosaicSupplyChange -) -> bytearray: + ctx: Context, + public_key: bytes, + common: NEMTransactionCommon, + change: NEMMosaicSupplyChange, +) -> bytes: await layout.ask_supply_change(ctx, common, change) return serialize.serialize_mosaic_supply_change(common, change, public_key) diff --git a/core/src/apps/nem/mosaic/helpers.py b/core/src/apps/nem/mosaic/helpers.py index af56432a7..e7a233554 100644 --- a/core/src/apps/nem/mosaic/helpers.py +++ b/core/src/apps/nem/mosaic/helpers.py @@ -1,15 +1,24 @@ -from .nem_mosaics import mosaics +from typing import TYPE_CHECKING +from .nem_mosaics import mosaics_iterator -def get_mosaic_definition(namespace_name: str, mosaic_name: str, network: int) -> dict: - for m in mosaics: - if namespace_name == m["namespace"] and mosaic_name == m["mosaic"]: - if ("networks" not in m) or (network in m["networks"]): - return m +if TYPE_CHECKING: + from trezor.messages import NEMMosaic + + from .nem_mosaics import Mosaic + + +def get_mosaic_definition( + namespace_name: str, mosaic_name: str, network: int +) -> Mosaic | None: + for mosaic in mosaics_iterator(): + if namespace_name == mosaic.namespace and mosaic_name == mosaic.mosaic: + if (mosaic.networks is None) or (network in mosaic.networks): + return mosaic return None -def is_nem_xem_mosaic(namespace_name: str, mosaic_name: str) -> bool: - if namespace_name == "nem" and mosaic_name == "xem": +def is_nem_xem_mosaic(mosaic: Mosaic | NEMMosaic) -> bool: + if mosaic.namespace == "nem" and mosaic.mosaic == "xem": return True return False diff --git a/core/src/apps/nem/mosaic/layout.py b/core/src/apps/nem/mosaic/layout.py index f535f887f..00acabfe1 100644 --- a/core/src/apps/nem/mosaic/layout.py +++ b/core/src/apps/nem/mosaic/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui from trezor.enums import NEMMosaicLevy, NEMSupplyChangeType from trezor.messages import ( @@ -15,10 +17,13 @@ from ..layout import ( require_confirm_text, ) +if TYPE_CHECKING: + from trezor.wire import Context + async def ask_mosaic_creation( - ctx, common: NEMTransactionCommon, creation: NEMMosaicCreation -): + ctx: Context, common: NEMTransactionCommon, creation: NEMMosaicCreation +) -> None: await require_confirm_content(ctx, "Create mosaic", _creation_message(creation)) await require_confirm_properties(ctx, creation.definition) await require_confirm_fee(ctx, "Confirm creation fee", creation.fee) @@ -27,8 +32,8 @@ async def ask_mosaic_creation( async def ask_supply_change( - ctx, common: NEMTransactionCommon, change: NEMMosaicSupplyChange -): + ctx: Context, common: NEMTransactionCommon, change: NEMMosaicSupplyChange +) -> None: await require_confirm_content(ctx, "Supply change", _supply_message(change)) if change.type == NEMSupplyChangeType.SupplyChange_Decrease: msg = "Decrease supply by " + str(change.delta) + " whole units?" @@ -41,21 +46,23 @@ async def ask_supply_change( await require_confirm_final(ctx, common.fee) -def _creation_message(mosaic_creation): +def _creation_message(mosaic_creation: NEMMosaicCreation) -> list[tuple[str, str]]: return [ ("Create mosaic", mosaic_creation.definition.mosaic), ("under namespace", mosaic_creation.definition.namespace), ] -def _supply_message(supply_change): +def _supply_message(supply_change: NEMMosaicSupplyChange) -> list[tuple[str, str]]: return [ ("Modify supply for", supply_change.mosaic), ("under namespace", supply_change.namespace), ] -async def require_confirm_properties(ctx, definition: NEMMosaicDefinition): +async def require_confirm_properties( + ctx: Context, definition: NEMMosaicDefinition +) -> None: properties = [] # description @@ -81,6 +88,11 @@ async def require_confirm_properties(ctx, definition: NEMMosaicDefinition): # levy if definition.levy: + # asserts below checked in nem.validators._validate_mosaic_creation + assert definition.levy_address is not None + assert definition.levy_namespace is not None + assert definition.levy_mosaic is not None + properties.append(("Levy recipient:", definition.levy_address)) properties.append(("Levy fee:", str(definition.fee))) diff --git a/core/src/apps/nem/mosaic/nem_mosaics.py b/core/src/apps/nem/mosaic/nem_mosaics.py index 72f2b6397..501f6e2d3 100644 --- a/core/src/apps/nem/mosaic/nem_mosaics.py +++ b/core/src/apps/nem/mosaic/nem_mosaics.py @@ -1,60 +1,102 @@ # generated from nem_mosaics.py.mako # do not edit manually! -mosaics = [ - { - "name": "NEM", - "ticker": " XEM", - "namespace": "nem", - "mosaic": "xem", - "divisibility": 6, - }, - { - "name": "DIMCOIN", - "ticker": " DIM", - "namespace": "dim", - "mosaic": "coin", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 10, - "levy_namespace": "dim", - "levy_mosaic": "coin", - "networks": [104], - }, - { - "name": "DIM TOKEN", - "ticker": " DIMTOK", - "namespace": "dim", - "mosaic": "token", - "divisibility": 6, - "networks": [104], - }, - { - "name": "Breeze Token", - "ticker": " BREEZE", - "namespace": "breeze", - "mosaic": "breeze-token", - "divisibility": 0, - "networks": [104], - }, - { - "name": "PacNEM Game Credits", - "ticker": " PAC:HRT", - "namespace": "pacnem", - "mosaic": "heart", - "divisibility": 0, - "networks": [104], - }, - { - "name": "PacNEM Score Tokens", - "ticker": " PAC:CHS", - "namespace": "pacnem", - "mosaic": "cheese", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 100, - "levy_namespace": "nem", - "levy_mosaic": "xem", - "networks": [104], - }, -] +from typing import Iterator + +from trezor.enums import NEMMosaicLevy + + +class MosaicLevy: + def __init__( + self, + type: NEMMosaicLevy, + fee: int, + namespace: str, + mosaic: str, + ) -> None: + self.type = type + self.fee = fee + self.namespace = namespace + self.mosaic = mosaic + + +class Mosaic: + def __init__( + self, + name: str, + ticker: str, + namespace: str, + mosaic: str, + divisibility: int, + levy: MosaicLevy | None = None, + networks: tuple[int, ...] | None = None, + ) -> None: + self.name = name + self.ticker = ticker + self.namespace = namespace + self.mosaic = mosaic + self.divisibility = divisibility + self.levy = levy + self.networks = networks + + +def mosaics_iterator() -> Iterator[Mosaic]: + yield Mosaic( + name="NEM", + ticker=" XEM", + namespace="nem", + mosaic="xem", + divisibility=6, + ) + yield Mosaic( + name="DIMCOIN", + ticker=" DIM", + namespace="dim", + mosaic="coin", + divisibility=6, + levy=MosaicLevy( + type=NEMMosaicLevy.MosaicLevy_Percentile, + fee=10, + namespace="dim", + mosaic="coin", + ), + networks=(104,), + ) + yield Mosaic( + name="DIM TOKEN", + ticker=" DIMTOK", + namespace="dim", + mosaic="token", + divisibility=6, + networks=(104,), + ) + yield Mosaic( + name="Breeze Token", + ticker=" BREEZE", + namespace="breeze", + mosaic="breeze-token", + divisibility=0, + networks=(104,), + ) + yield Mosaic( + name="PacNEM Game Credits", + ticker=" PAC:HRT", + namespace="pacnem", + mosaic="heart", + divisibility=0, + networks=(104,), + ) + yield Mosaic( + name="PacNEM Score Tokens", + ticker=" PAC:CHS", + namespace="pacnem", + mosaic="cheese", + divisibility=6, + levy=MosaicLevy( + type=NEMMosaicLevy.MosaicLevy_Percentile, + fee=100, + namespace="nem", + mosaic="xem", + ), + networks=(104,), + ) diff --git a/core/src/apps/nem/mosaic/nem_mosaics.py.mako b/core/src/apps/nem/mosaic/nem_mosaics.py.mako index 284fd924e..d9a2563db 100644 --- a/core/src/apps/nem/mosaic/nem_mosaics.py.mako +++ b/core/src/apps/nem/mosaic/nem_mosaics.py.mako @@ -1,29 +1,63 @@ # generated from nem_mosaics.py.mako # do not edit manually! -<% -ATTRIBUTES = ( - "name", - "ticker", - "namespace", - "mosaic", - "divisibility", - "levy", - "fee", - "levy_namespace", - "levy_mosaic", - "networks", -) -%>\ - -mosaics = [ + +from typing import Iterator + +from trezor.enums import NEMMosaicLevy + + +class MosaicLevy: + def __init__( + self, + type: NEMMosaicLevy, + fee: int, + namespace: str, + mosaic: str, + ) -> None: + self.type = type + self.fee = fee + self.namespace = namespace + self.mosaic = mosaic + + +class Mosaic: + def __init__( + self, + name: str, + ticker: str, + namespace: str, + mosaic: str, + divisibility: int, + levy: MosaicLevy | None = None, + networks: tuple[int, ...] | None = None, + ) -> None: + self.name = name + self.ticker = ticker + self.namespace = namespace + self.mosaic = mosaic + self.divisibility = divisibility + self.levy = levy + self.networks = networks + + +def mosaics_iterator() -> Iterator[Mosaic]: % for m in supported_on("trezor2", nem): -<% m.ticker = " " + m.ticker %>\ - { - % for attr in ATTRIBUTES: - % if attr in m: - "${attr}": ${black_repr(m[attr])}, - % endif - % endfor - }, + yield Mosaic( + name="${m.name}", + ticker=" ${m.ticker}", + namespace="${m.namespace}", + mosaic="${m.mosaic}", + divisibility=${m.divisibility}, +% if "levy" in m: + levy=MosaicLevy( + type=NEMMosaicLevy.${m.levy}, + fee=${m.fee}, + namespace="${m.levy_namespace}", + mosaic="${m.levy_mosaic}", + ), +% endif +% if "networks" in m: + networks=${tuple(m.networks)}, +% endif + ) % endfor -] diff --git a/core/src/apps/nem/mosaic/serialize.py b/core/src/apps/nem/mosaic/serialize.py index 1c86e0912..a043e815a 100644 --- a/core/src/apps/nem/mosaic/serialize.py +++ b/core/src/apps/nem/mosaic/serialize.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import ( NEMMosaicCreation, NEMMosaicSupplyChange, @@ -15,10 +17,13 @@ from ..writers import ( write_uint64_le, ) +if TYPE_CHECKING: + from trezor.utils import Writer + def serialize_mosaic_creation( common: NEMTransactionCommon, creation: NEMMosaicCreation, public_key: bytes -): +) -> bytes: w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_CREATION) mosaics_w = bytearray() @@ -38,6 +43,11 @@ def serialize_mosaic_creation( _write_property(mosaics_w, "transferable", creation.definition.transferable) if creation.definition.levy: + # all below asserts checked by nem.validators._validate_mosaic_creation + assert creation.definition.levy_namespace is not None + assert creation.definition.levy_mosaic is not None + assert creation.definition.levy_address is not None + assert creation.definition.fee is not None levy_identifier_w = bytearray() write_bytes_with_len( @@ -67,7 +77,7 @@ def serialize_mosaic_creation( def serialize_mosaic_supply_change( common: NEMTransactionCommon, change: NEMMosaicSupplyChange, public_key: bytes -): +) -> bytes: w = serialize_tx_common( common, public_key, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE ) @@ -83,7 +93,7 @@ def serialize_mosaic_supply_change( return w -def _write_property(w: bytearray, name: str, value): +def _write_property(w: Writer, name: str, value: int | bool | str | None) -> None: if value is None: if name in ("divisibility", "initialSupply"): value = 0 @@ -96,10 +106,10 @@ def _write_property(w: bytearray, name: str, value): value = "false" elif type(value) == int: value = str(value) - if type(value) != str: + if not isinstance(value, str): raise ValueError("Incompatible value type") - name = name.encode() - value = value.encode() - write_uint32_le(w, 4 + len(name) + 4 + len(value)) - write_bytes_with_len(w, name) - write_bytes_with_len(w, value) + byte_name = name.encode() + byte_value = value.encode() + write_uint32_le(w, 4 + len(byte_name) + 4 + len(byte_value)) + write_bytes_with_len(w, byte_name) + write_bytes_with_len(w, byte_value) diff --git a/core/src/apps/nem/multisig/__init__.py b/core/src/apps/nem/multisig/__init__.py index f9859fb92..417b4736e 100644 --- a/core/src/apps/nem/multisig/__init__.py +++ b/core/src/apps/nem/multisig/__init__.py @@ -1,29 +1,34 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMAggregateModification, NEMSignTx, NEMTransactionCommon from . import layout, serialize +if TYPE_CHECKING: + from trezor.wire import Context + -async def ask(ctx, msg: NEMSignTx): +async def ask(ctx: Context, msg: NEMSignTx) -> None: await layout.ask_multisig(ctx, msg) -def initiate(public_key, common: NEMTransactionCommon, inner_tx: bytes) -> bytes: +def initiate(public_key: bytes, common: NEMTransactionCommon, inner_tx: bytes) -> bytes: return serialize.serialize_multisig(common, public_key, inner_tx) def cosign( - public_key, common: NEMTransactionCommon, inner_tx: bytes, signer: bytes + public_key: bytes, common: NEMTransactionCommon, inner_tx: bytes, signer: bytes ) -> bytes: return serialize.serialize_multisig_signature(common, public_key, inner_tx, signer) async def aggregate_modification( - ctx, + ctx: Context, public_key: bytes, common: NEMTransactionCommon, aggr: NEMAggregateModification, multisig: bool, -): +) -> bytes: await layout.ask_aggregate_modification(ctx, common, aggr, multisig) w = serialize.serialize_aggregate_modification(common, aggr, public_key) diff --git a/core/src/apps/nem/multisig/layout.py b/core/src/apps/nem/multisig/layout.py index b45fa1a7a..13b747276 100644 --- a/core/src/apps/nem/multisig/layout.py +++ b/core/src/apps/nem/multisig/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui from trezor.crypto import nem from trezor.enums import ButtonRequestType, NEMModificationType @@ -6,8 +8,13 @@ from trezor.ui.layouts import confirm_address from ..layout import require_confirm_fee, require_confirm_final, require_confirm_text +if TYPE_CHECKING: + from trezor.wire import Context + -async def ask_multisig(ctx, msg: NEMSignTx): +async def ask_multisig(ctx: Context, msg: NEMSignTx) -> None: + assert msg.multisig is not None # sign_tx + assert msg.multisig.signer is not None # sign_tx address = nem.compute_address(msg.multisig.signer, msg.transaction.network) if msg.cosigning: await _require_confirm_address(ctx, "Cosign transaction for", address) @@ -17,8 +24,11 @@ async def ask_multisig(ctx, msg: NEMSignTx): async def ask_aggregate_modification( - ctx, common: NEMTransactionCommon, mod: NEMAggregateModification, multisig: bool -): + ctx: Context, + common: NEMTransactionCommon, + mod: NEMAggregateModification, + multisig: bool, +) -> None: if not multisig: await require_confirm_text(ctx, "Convert account to multisig account?") @@ -40,7 +50,7 @@ async def ask_aggregate_modification( await require_confirm_final(ctx, common.fee) -async def _require_confirm_address(ctx, action: str, address: str): +async def _require_confirm_address(ctx: Context, action: str, address: str) -> None: await confirm_address( ctx, br_type="confirm_multisig", diff --git a/core/src/apps/nem/multisig/serialize.py b/core/src/apps/nem/multisig/serialize.py index 6f7cb09eb..c2039f8fd 100644 --- a/core/src/apps/nem/multisig/serialize.py +++ b/core/src/apps/nem/multisig/serialize.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import hashlib, nem from trezor.messages import NEMAggregateModification, NEMTransactionCommon @@ -8,8 +10,13 @@ from ..helpers import ( ) from ..writers import serialize_tx_common, write_bytes_with_len, write_uint32_le +if TYPE_CHECKING: + from trezor.utils import Writer + -def serialize_multisig(common: NEMTransactionCommon, public_key: bytes, inner: bytes): +def serialize_multisig( + common: NEMTransactionCommon, public_key: bytes, inner: bytes +) -> bytes: w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG) write_bytes_with_len(w, inner) return w @@ -20,20 +27,20 @@ def serialize_multisig_signature( public_key: bytes, inner: bytes, address_public_key: bytes, -): +) -> bytes: w = serialize_tx_common(common, public_key, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE) digest = hashlib.sha3_256(inner, keccak=True).digest() address = nem.compute_address(address_public_key, common.network) write_uint32_le(w, 4 + len(digest)) write_bytes_with_len(w, digest) - write_bytes_with_len(w, address) + write_bytes_with_len(w, address.encode()) return w def serialize_aggregate_modification( common: NEMTransactionCommon, mod: NEMAggregateModification, public_key: bytes -): +) -> bytearray: version = common.network << 24 | 1 if mod.relative_change: version = common.network << 24 | 2 @@ -46,14 +53,13 @@ def serialize_aggregate_modification( def write_cosignatory_modification( - w: bytearray, cosignatory_type: int, cosignatory_pubkey: bytes -): + w: Writer, cosignatory_type: int, cosignatory_pubkey: bytes +) -> None: write_uint32_le(w, 4 + 4 + len(cosignatory_pubkey)) write_uint32_le(w, cosignatory_type) write_bytes_with_len(w, cosignatory_pubkey) - return w -def write_minimum_cosignatories(w: bytearray, relative_change: int): +def write_minimum_cosignatories(w: Writer, relative_change: int) -> None: write_uint32_le(w, 4) write_uint32_le(w, relative_change) diff --git a/core/src/apps/nem/namespace/__init__.py b/core/src/apps/nem/namespace/__init__.py index 1cc3e3f5e..85c3c6364 100644 --- a/core/src/apps/nem/namespace/__init__.py +++ b/core/src/apps/nem/namespace/__init__.py @@ -1,13 +1,18 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon from . import layout, serialize +if TYPE_CHECKING: + from trezor.wire import Context + async def namespace( - ctx, + ctx: Context, public_key: bytes, common: NEMTransactionCommon, namespace: NEMProvisionNamespace, -) -> bytearray: +) -> bytes: await layout.ask_provision_namespace(ctx, common, namespace) return serialize.serialize_provision_namespace(common, namespace, public_key) diff --git a/core/src/apps/nem/namespace/layout.py b/core/src/apps/nem/namespace/layout.py index 5c87aab3f..ceef79bf1 100644 --- a/core/src/apps/nem/namespace/layout.py +++ b/core/src/apps/nem/namespace/layout.py @@ -1,11 +1,16 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMProvisionNamespace, NEMTransactionCommon from ..layout import require_confirm_content, require_confirm_fee, require_confirm_final +if TYPE_CHECKING: + from trezor.wire import Context + async def ask_provision_namespace( - ctx, common: NEMTransactionCommon, namespace: NEMProvisionNamespace -): + ctx: Context, common: NEMTransactionCommon, namespace: NEMProvisionNamespace +) -> None: if namespace.parent: content = [ ("Create namespace", namespace.namespace), diff --git a/core/src/apps/nem/namespace/serialize.py b/core/src/apps/nem/namespace/serialize.py index 3ee850822..abdf6c405 100644 --- a/core/src/apps/nem/namespace/serialize.py +++ b/core/src/apps/nem/namespace/serialize.py @@ -11,7 +11,7 @@ from ..writers import ( def serialize_provision_namespace( common: NEMTransactionCommon, namespace: NEMProvisionNamespace, public_key: bytes -) -> bytearray: +) -> bytes: tx = serialize_tx_common( common, public_key, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE ) diff --git a/core/src/apps/nem/sign_tx.py b/core/src/apps/nem/sign_tx.py index ac9684e0e..c2551743e 100644 --- a/core/src/apps/nem/sign_tx.py +++ b/core/src/apps/nem/sign_tx.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto.curve import ed25519 from trezor.messages import NEMSignedTx, NEMSignTx @@ -10,9 +12,12 @@ from . import CURVE, PATTERNS, SLIP44_ID, mosaic, multisig, namespace, transfer from .helpers import NEM_HASH_ALG, check_path from .validators import validate +if TYPE_CHECKING: + from apps.common.keychain import Keychain + @with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) -async def sign_tx(ctx, msg: NEMSignTx, keychain): +async def sign_tx(ctx: wire.Context, msg: NEMSignTx, keychain: Keychain) -> NEMSignedTx: validate(msg) await validate_path( @@ -25,6 +30,8 @@ async def sign_tx(ctx, msg: NEMSignTx, keychain): node = keychain.derive(msg.transaction.address_n) if msg.multisig: + if msg.multisig.signer is None: + raise wire.DataError("No signer provided") public_key = msg.multisig.signer common = msg.multisig await multisig.ask(ctx, msg) @@ -58,6 +65,7 @@ async def sign_tx(ctx, msg: NEMSignTx, keychain): if msg.multisig: # wrap transaction in multisig wrapper if msg.cosigning: + assert msg.multisig.signer is not None tx = multisig.cosign( seed.remove_ed25519_prefix(node.public_key()), msg.transaction, diff --git a/core/src/apps/nem/transfer/__init__.py b/core/src/apps/nem/transfer/__init__.py index ab111df8e..5ff1ca559 100644 --- a/core/src/apps/nem/transfer/__init__.py +++ b/core/src/apps/nem/transfer/__init__.py @@ -1,15 +1,25 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMImportanceTransfer, NEMTransactionCommon, NEMTransfer from . import layout, serialize +if TYPE_CHECKING: + from trezor.wire import Context + from trezor.crypto import bip32 + async def transfer( - ctx, public_key: bytes, common: NEMTransactionCommon, transfer: NEMTransfer, node -): + ctx: Context, + public_key: bytes, + common: NEMTransactionCommon, + transfer: NEMTransfer, + node: bip32.HDNode, +) -> bytes: transfer.mosaics = serialize.canonicalize_mosaics(transfer.mosaics) payload, encrypted = serialize.get_transfer_payload(transfer, node) - await layout.ask_transfer(ctx, common, transfer, payload, encrypted) + await layout.ask_transfer(ctx, common, transfer, encrypted) w = serialize.serialize_transfer(common, transfer, public_key, payload, encrypted) for mosaic in transfer.mosaics: @@ -18,7 +28,10 @@ async def transfer( async def importance_transfer( - ctx, public_key: bytes, common: NEMTransactionCommon, imp: NEMImportanceTransfer -): + ctx: Context, + public_key: bytes, + common: NEMTransactionCommon, + imp: NEMImportanceTransfer, +) -> bytes: await layout.ask_importance_transfer(ctx, common, imp) return serialize.serialize_importance_transfer(common, imp, public_key) diff --git a/core/src/apps/nem/transfer/layout.py b/core/src/apps/nem/transfer/layout.py index a86e8e75e..4e0d0bd03 100644 --- a/core/src/apps/nem/transfer/layout.py +++ b/core/src/apps/nem/transfer/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui from trezor.enums import ButtonRequestType, NEMImportanceTransferMode, NEMMosaicLevy from trezor.messages import ( @@ -22,15 +24,18 @@ from ..helpers import ( from ..layout import require_confirm_final, require_confirm_text from ..mosaic.helpers import get_mosaic_definition, is_nem_xem_mosaic +if TYPE_CHECKING: + from trezor.wire import Context + from ..mosaic.nem_mosaics import MosaicLevy + async def ask_transfer( - ctx, + ctx: Context, common: NEMTransactionCommon, transfer: NEMTransfer, - payload: bytes, encrypted: bool, -): - if payload: +) -> None: + if transfer.payload: await _require_confirm_payload(ctx, transfer.payload, encrypted) for mosaic in transfer.mosaics: await ask_transfer_mosaic(ctx, common, transfer, mosaic) @@ -39,9 +44,9 @@ async def ask_transfer( async def ask_transfer_mosaic( - ctx, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic -): - if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic): + ctx: Context, common: NEMTransactionCommon, transfer: NEMTransfer, mosaic: NEMMosaic +) -> None: + if is_nem_xem_mosaic(mosaic): return definition = get_mosaic_definition(mosaic.namespace, mosaic.mosaic, common.network) @@ -55,15 +60,19 @@ async def ask_transfer_mosaic( props=[ ( "Confirm transfer of", - format_amount(mosaic_quantity, definition["divisibility"]) - + definition["ticker"], + format_amount(mosaic_quantity, definition.divisibility) + + definition.ticker, ), - ("of", definition["name"]), + ("of", definition.name), ], ) - if "levy" in definition and "fee" in definition: - levy_msg = _get_levy_msg(definition, mosaic_quantity, common.network) + if definition.levy is not None: + levy_fee = _get_levy_fee(definition.levy, mosaic_quantity) + levy_msg = ( + format_amount(levy_fee, definition.divisibility) + definition.ticker + ) + await confirm_properties( ctx, "confirm_mosaic_levy", @@ -96,37 +105,28 @@ async def ask_transfer_mosaic( ) -def _get_xem_amount(transfer: NEMTransfer): +def _get_xem_amount(transfer: NEMTransfer) -> int: # if mosaics are empty the transfer.amount denotes the xem amount if not transfer.mosaics: return transfer.amount # otherwise xem amount is taken from the nem xem mosaic if present for mosaic in transfer.mosaics: - if is_nem_xem_mosaic(mosaic.namespace, mosaic.mosaic): + if is_nem_xem_mosaic(mosaic): return mosaic.quantity * transfer.amount // NEM_MOSAIC_AMOUNT_DIVISOR # if there are mosaics but do not include xem, 0 xem is sent return 0 -def _get_levy_msg(mosaic_definition, quantity: int, network: int) -> str: - levy_definition = get_mosaic_definition( - mosaic_definition["levy_namespace"], mosaic_definition["levy_mosaic"], network - ) - if mosaic_definition["levy"] == NEMMosaicLevy.MosaicLevy_Absolute: - levy_fee = mosaic_definition["fee"] +def _get_levy_fee(levy: MosaicLevy, quantity: int) -> int: + if levy.type == NEMMosaicLevy.MosaicLevy_Absolute: + return levy.fee else: - levy_fee = ( - quantity * mosaic_definition["fee"] // NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE - ) - return ( - format_amount(levy_fee, levy_definition["divisibility"]) - + levy_definition["ticker"] - ) + return quantity * levy.fee // NEM_LEVY_PERCENTILE_DIVISOR_ABSOLUTE async def ask_importance_transfer( - ctx, common: NEMTransactionCommon, imp: NEMImportanceTransfer -): + ctx: Context, common: NEMTransactionCommon, imp: NEMImportanceTransfer +) -> None: if imp.mode == NEMImportanceTransferMode.ImportanceTransfer_Activate: m = "Activate" else: @@ -135,7 +135,7 @@ async def ask_importance_transfer( await require_confirm_final(ctx, common.fee) -async def _require_confirm_transfer(ctx, recipient, value): +async def _require_confirm_transfer(ctx: Context, recipient: str, value: int) -> None: await confirm_output( ctx, recipient, @@ -146,16 +146,15 @@ async def _require_confirm_transfer(ctx, recipient, value): ) -async def _require_confirm_payload(ctx, payload: bytearray, encrypt=False): - payload = bytes(payload).decode() - subtitle = "Encrypted:" if encrypt else "Unencrypted:" - +async def _require_confirm_payload( + ctx: Context, payload: bytes, encrypted: bool = False +) -> None: await confirm_text( ctx, "confirm_payload", title="Confirm payload", - description=subtitle, - data=payload, - icon_color=ui.GREEN if encrypt else ui.RED, + description="Encrypted:" if encrypted else "Unencrypted:", + data=bytes(payload).decode(), + icon_color=ui.GREEN if encrypted else ui.RED, br_code=ButtonRequestType.ConfirmOutput, ) diff --git a/core/src/apps/nem/transfer/serialize.py b/core/src/apps/nem/transfer/serialize.py index 7ab7985ed..ad788cbee 100644 --- a/core/src/apps/nem/transfer/serialize.py +++ b/core/src/apps/nem/transfer/serialize.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import random from trezor.messages import ( NEMImportanceTransfer, @@ -19,13 +21,17 @@ from ..writers import ( write_uint64_le, ) +if TYPE_CHECKING: + from trezor.crypto import bip32 + from trezor.utils import Writer + def serialize_transfer( common: NEMTransactionCommon, transfer: NEMTransfer, public_key: bytes, - payload: bytes = None, - encrypted: bool = False, + payload: bytes, + encrypted: bool, ) -> bytearray: tx = serialize_tx_common( common, @@ -54,7 +60,7 @@ def serialize_transfer( return tx -def serialize_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int): +def serialize_mosaic(w: Writer, namespace: str, mosaic: str, quantity: int) -> None: identifier_w = bytearray() write_bytes_with_len(identifier_w, namespace.encode()) write_bytes_with_len(identifier_w, mosaic.encode()) @@ -68,7 +74,7 @@ def serialize_mosaic(w: bytearray, namespace: str, mosaic: str, quantity: int): def serialize_importance_transfer( common: NEMTransactionCommon, imp: NEMImportanceTransfer, public_key: bytes -) -> bytearray: +) -> bytes: w = serialize_tx_common( common, public_key, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER ) @@ -78,32 +84,32 @@ def serialize_importance_transfer( return w -def get_transfer_payload(transfer: NEMTransfer, node) -> [bytes, bool]: - payload = transfer.payload - encrypted = False +def get_transfer_payload( + transfer: NEMTransfer, node: bip32.HDNode +) -> tuple[bytes, bool]: if transfer.public_key is not None: - if payload is None: + if not transfer.payload: raise ValueError("Public key provided but no payload to encrypt") - payload = _encrypt(node, transfer.public_key, transfer.payload) - encrypted = True - - return payload, encrypted + encrypted_payload = _encrypt(node, transfer.public_key, transfer.payload) + return encrypted_payload, True + else: + return transfer.payload, False -def _encrypt(node, public_key: bytes, payload: bytes) -> bytes: +def _encrypt(node: bip32.HDNode, public_key: bytes, payload: bytes) -> bytes: salt = random.bytes(NEM_SALT_SIZE) iv = random.bytes(AES_BLOCK_SIZE) encrypted = node.nem_encrypt(public_key, iv, salt, payload) return iv + salt + encrypted -def _get_version(network, mosaics=None) -> int: +def _get_version(network: int, mosaics: list[NEMMosaic] | None = None) -> int: if mosaics: return network << 24 | 2 return network << 24 | 1 -def canonicalize_mosaics(mosaics: list): +def canonicalize_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]: if len(mosaics) <= 1: return mosaics mosaics = merge_mosaics(mosaics) @@ -116,10 +122,10 @@ def are_mosaics_equal(a: NEMMosaic, b: NEMMosaic) -> bool: return False -def merge_mosaics(mosaics: list) -> list: +def merge_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]: if not mosaics: return [] - ret = [] + ret: list[NEMMosaic] = [] for i in mosaics: found = False for k, y in enumerate(ret): @@ -131,5 +137,5 @@ def merge_mosaics(mosaics: list) -> list: return ret -def sort_mosaics(mosaics: list) -> list: +def sort_mosaics(mosaics: list[NEMMosaic]) -> list[NEMMosaic]: return sorted(mosaics, key=lambda m: (m.namespace, m.mosaic)) diff --git a/core/src/apps/nem/validators.py b/core/src/apps/nem/validators.py index e2d218504..f9d0c8aee 100644 --- a/core/src/apps/nem/validators.py +++ b/core/src/apps/nem/validators.py @@ -1,5 +1,5 @@ from trezor.crypto import nem -from trezor.enums import NEMModificationType, NEMSupplyChangeType +from trezor.enums import NEMModificationType from trezor.messages import ( NEMAggregateModification, NEMImportanceTransfer, @@ -24,15 +24,12 @@ from .helpers import ( ) -def validate(msg: NEMSignTx): - if msg.transaction is None: - raise ProcessError("No common provided") - +def validate(msg: NEMSignTx) -> None: _validate_single_tx(msg) _validate_common(msg.transaction) if msg.multisig: - _validate_common(msg.multisig, True) + _validate_common(msg.multisig, inner=True) _validate_multisig(msg.multisig, msg.transaction.network) if not msg.multisig and msg.cosigning: raise ProcessError("No multisig transaction to cosign") @@ -53,15 +50,12 @@ def validate(msg: NEMSignTx): _validate_importance_transfer(msg.importance_transfer) -def validate_network(network: int) -> int: - if network is None: - return NEM_NETWORK_MAINNET +def validate_network(network: int) -> None: if network not in (NEM_NETWORK_MAINNET, NEM_NETWORK_TESTNET, NEM_NETWORK_MIJIN): raise ProcessError("Invalid NEM network") - return network -def _validate_single_tx(msg: NEMSignTx): +def _validate_single_tx(msg: NEMSignTx) -> None: # ensure exactly one transaction is provided tx_count = ( bool(msg.transfer) @@ -77,16 +71,10 @@ def _validate_single_tx(msg: NEMSignTx): raise ProcessError("More than one transaction provided") -def _validate_common(common: NEMTransactionCommon, inner: bool = False): - common.network = validate_network(common.network) +def _validate_common(common: NEMTransactionCommon, inner: bool = False) -> None: + validate_network(common.network) err = None - if common.timestamp is None: - err = "timestamp" - if common.fee is None: - err = "fee" - if common.deadline is None: - err = "deadline" if not inner and common.signer: raise ProcessError("Signer not allowed in outer transaction") @@ -106,22 +94,20 @@ def _validate_common(common: NEMTransactionCommon, inner: bool = False): ) -def _validate_public_key(public_key: bytes, err_msg: str): +def _validate_public_key(public_key: bytes | None, err_msg: str) -> None: if not public_key: raise ProcessError(f"{err_msg} (none provided)") if len(public_key) != NEM_PUBLIC_KEY_SIZE: raise ProcessError(f"{err_msg} (invalid length)") -def _validate_importance_transfer(importance_transfer: NEMImportanceTransfer): - if importance_transfer.mode is None: - raise ProcessError("No mode provided") +def _validate_importance_transfer(importance_transfer: NEMImportanceTransfer) -> None: _validate_public_key( importance_transfer.public_key, "Invalid remote account public key provided" ) -def _validate_multisig(multisig: NEMTransactionCommon, network: int): +def _validate_multisig(multisig: NEMTransactionCommon, network: int) -> None: if multisig.network != network: raise ProcessError("Inner transaction network is different") _validate_public_key(multisig.signer, "Invalid multisig signer public key provided") @@ -129,48 +115,22 @@ def _validate_multisig(multisig: NEMTransactionCommon, network: int): def _validate_aggregate_modification( aggregate_modification: NEMAggregateModification, creation: bool = False -): +) -> None: if creation and not aggregate_modification.modifications: raise ProcessError("No modifications provided") for m in aggregate_modification.modifications: - if not m.type: - raise ProcessError("No modification type provided") - if m.type not in ( - NEMModificationType.CosignatoryModification_Add, - NEMModificationType.CosignatoryModification_Delete, - ): - raise ProcessError("Unknown aggregate modification") if creation and m.type == NEMModificationType.CosignatoryModification_Delete: raise ProcessError("Cannot remove cosignatory when converting account") _validate_public_key(m.public_key, "Invalid cosignatory public key provided") -def _validate_supply_change(supply_change: NEMMosaicSupplyChange): - if supply_change.namespace is None: - raise ProcessError("No namespace provided") - if supply_change.mosaic is None: - raise ProcessError("No mosaic provided") - if supply_change.type is None: - raise ProcessError("No type provided") - elif supply_change.type not in [ - NEMSupplyChangeType.SupplyChange_Decrease, - NEMSupplyChangeType.SupplyChange_Increase, - ]: - raise ProcessError("Invalid supply change type") - if supply_change.delta is None: - raise ProcessError("No delta provided") - - -def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int): - if mosaic_creation.definition is None: - raise ProcessError("No mosaic definition provided") - if mosaic_creation.sink is None: - raise ProcessError("No creation sink provided") - if mosaic_creation.fee is None: - raise ProcessError("No creation sink fee provided") +def _validate_supply_change(supply_change: NEMMosaicSupplyChange) -> None: + pass + +def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int) -> None: if not nem.validate_address(mosaic_creation.sink, network): raise ProcessError("Invalid creation sink address") @@ -181,11 +141,6 @@ def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int): if mosaic_creation.definition.networks: raise ProcessError("Networks not allowed in mosaic creation transactions") - if mosaic_creation.definition.namespace is None: - raise ProcessError("No mosaic namespace provided") - if mosaic_creation.definition.mosaic is None: - raise ProcessError("No mosaic name provided") - if ( mosaic_creation.definition.supply is not None and mosaic_creation.definition.divisibility is None @@ -233,27 +188,15 @@ def _validate_mosaic_creation(mosaic_creation: NEMMosaicCreation, network: int): def _validate_provision_namespace( provision_namespace: NEMProvisionNamespace, network: int -): - if provision_namespace.namespace is None: - raise ProcessError("No namespace provided") - if provision_namespace.sink is None: - raise ProcessError("No rental sink provided") - if provision_namespace.fee is None: - raise ProcessError("No rental sink fee provided") - +) -> None: if not nem.validate_address(provision_namespace.sink, network): raise ProcessError("Invalid rental sink address") -def _validate_transfer(transfer: NEMTransfer, network: int): - if transfer.recipient is None: - raise ProcessError("No recipient provided") - if transfer.amount is None: - raise ProcessError("No amount provided") - +def _validate_transfer(transfer: NEMTransfer, network: int) -> None: if transfer.public_key is not None: _validate_public_key(transfer.public_key, "Invalid recipient public key") - if transfer.payload is None: + if not transfer.payload: raise ProcessError("Public key provided but no payload to encrypt") if transfer.payload: @@ -267,11 +210,3 @@ def _validate_transfer(transfer: NEMTransfer, network: int): if not nem.validate_address(transfer.recipient, network): raise ProcessError("Invalid recipient address") - - for m in transfer.mosaics: - if m.namespace is None: - raise ProcessError("No mosaic namespace provided") - if m.mosaic is None: - raise ProcessError("No mosaic name provided") - if m.quantity is None: - raise ProcessError("No mosaic quantity provided") diff --git a/core/src/apps/nem/writers.py b/core/src/apps/nem/writers.py index 3e6a57d85..555581deb 100644 --- a/core/src/apps/nem/writers.py +++ b/core/src/apps/nem/writers.py @@ -1,13 +1,18 @@ +from typing import TYPE_CHECKING + from trezor.messages import NEMTransactionCommon from apps.common.writers import write_bytes_unchecked, write_uint32_le, write_uint64_le +if TYPE_CHECKING: + from trezor.utils import Writer + def serialize_tx_common( common: NEMTransactionCommon, - public_key: bytearray, + public_key: bytes, transaction_type: int, - version: int = None, + version: int | None = None, ) -> bytearray: w = bytearray() @@ -24,6 +29,6 @@ def serialize_tx_common( return w -def write_bytes_with_len(w, buf: bytes): +def write_bytes_with_len(w: Writer, buf: bytes) -> None: write_uint32_le(w, len(buf)) write_bytes_unchecked(w, buf) diff --git a/core/src/apps/ripple/base58_ripple.py b/core/src/apps/ripple/base58_ripple.py index 2ead40890..d9685648c 100644 --- a/core/src/apps/ripple/base58_ripple.py +++ b/core/src/apps/ripple/base58_ripple.py @@ -1,3 +1,5 @@ +from typing import Callable + from trezor.crypto import base58 # Ripple uses different 58 character alphabet than traditional base58 @@ -18,14 +20,18 @@ def decode(string: str) -> bytes: return base58.decode(string, alphabet=_ripple_alphabet) -def encode_check(data: bytes, digestfunc=base58.sha256d_32) -> str: +def encode_check( + data: bytes, digestfunc: Callable[[bytes], bytes] = base58.sha256d_32 +) -> str: """ Convert bytes to base58 encoded string, append checksum. """ return encode(data + digestfunc(data)) -def decode_check(string: str, digestfunc=base58.sha256d_32) -> bytes: +def decode_check( + string: str, digestfunc: Callable[[bytes], bytes] = base58.sha256d_32 +) -> bytes: """ Convert base58 encoded string to bytes and verify checksum. """ diff --git a/core/src/apps/ripple/get_address.py b/core/src/apps/ripple/get_address.py index 35898704e..2d5bc6af1 100644 --- a/core/src/apps/ripple/get_address.py +++ b/core/src/apps/ripple/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import RippleAddress, RippleGetAddress from trezor.ui.layouts import show_address @@ -6,9 +8,15 @@ from apps.common.keychain import auto_keychain from .helpers import address_from_public_key +if TYPE_CHECKING: + from apps.common.keychain import Keychain + from trezor.wire import Context + @auto_keychain(__name__) -async def get_address(ctx, msg: RippleGetAddress, keychain): +async def get_address( + ctx: Context, msg: RippleGetAddress, keychain: Keychain +) -> RippleAddress: await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) diff --git a/core/src/apps/ripple/helpers.py b/core/src/apps/ripple/helpers.py index d2ca3ede5..2e9ca61a6 100644 --- a/core/src/apps/ripple/helpers.py +++ b/core/src/apps/ripple/helpers.py @@ -45,7 +45,7 @@ def address_from_public_key(pubkey: bytes) -> str: return base58_ripple.encode_check(bytes(address)) -def decode_address(address: str): +def decode_address(address: str) -> bytes: """Returns so called Account ID""" adr = base58_ripple.decode_check(address) return adr[1:] diff --git a/core/src/apps/ripple/layout.py b/core/src/apps/ripple/layout.py index 8106ed726..91015f3b7 100644 --- a/core/src/apps/ripple/layout.py +++ b/core/src/apps/ripple/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.enums import ButtonRequestType from trezor.strings import format_amount from trezor.ui.layouts import confirm_metadata @@ -5,8 +7,11 @@ from trezor.ui.layouts.tt.altcoin import confirm_total_ripple from . import helpers +if TYPE_CHECKING: + from trezor.wire import Context + -async def require_confirm_fee(ctx, fee): +async def require_confirm_fee(ctx: Context, fee: int) -> None: await confirm_metadata( ctx, "confirm_fee", @@ -18,7 +23,7 @@ async def require_confirm_fee(ctx, fee): ) -async def require_confirm_destination_tag(ctx, tag): +async def require_confirm_destination_tag(ctx: Context, tag: int) -> None: await confirm_metadata( ctx, "confirm_destination_tag", @@ -30,5 +35,5 @@ async def require_confirm_destination_tag(ctx, tag): ) -async def require_confirm_tx(ctx, to, value): +async def require_confirm_tx(ctx: Context, to: str, value: int) -> None: await confirm_total_ripple(ctx, to, format_amount(value, helpers.DECIMALS)) diff --git a/core/src/apps/ripple/serialize.py b/core/src/apps/ripple/serialize.py index 0ae6afa9e..8f8c8a0ca 100644 --- a/core/src/apps/ripple/serialize.py +++ b/core/src/apps/ripple/serialize.py @@ -8,34 +8,51 @@ # the actual data follow. This currently only supports the Payment # transaction type and the fields that are required for it. +from typing import TYPE_CHECKING + from trezor.messages import RippleSignTx from . import helpers +if TYPE_CHECKING: + from trezor.utils import Writer + + +class RippleField: + def __init__(self, type: int, key: int) -> None: + self.type: int = type + self.key: int = key + + FIELD_TYPE_INT16 = 1 FIELD_TYPE_INT32 = 2 FIELD_TYPE_AMOUNT = 6 FIELD_TYPE_VL = 7 FIELD_TYPE_ACCOUNT = 8 -FIELDS_MAP = { - "account": {"type": FIELD_TYPE_ACCOUNT, "key": 1}, - "amount": {"type": FIELD_TYPE_AMOUNT, "key": 1}, - "destination": {"type": FIELD_TYPE_ACCOUNT, "key": 3}, - "fee": {"type": FIELD_TYPE_AMOUNT, "key": 8}, - "sequence": {"type": FIELD_TYPE_INT32, "key": 4}, - "type": {"type": FIELD_TYPE_INT16, "key": 2}, - "signingPubKey": {"type": FIELD_TYPE_VL, "key": 3}, - "flags": {"type": FIELD_TYPE_INT32, "key": 2}, - "txnSignature": {"type": FIELD_TYPE_VL, "key": 4}, - "lastLedgerSequence": {"type": FIELD_TYPE_INT32, "key": 27}, - "destinationTag": {"type": FIELD_TYPE_INT32, "key": 14}, +FIELDS_MAP: dict[str, RippleField] = { + "account": RippleField(type=FIELD_TYPE_ACCOUNT, key=1), + "amount": RippleField(type=FIELD_TYPE_AMOUNT, key=1), + "destination": RippleField(type=FIELD_TYPE_ACCOUNT, key=3), + "fee": RippleField(type=FIELD_TYPE_AMOUNT, key=8), + "sequence": RippleField(type=FIELD_TYPE_INT32, key=4), + "type": RippleField(type=FIELD_TYPE_INT16, key=2), + "signingPubKey": RippleField(type=FIELD_TYPE_VL, key=3), + "flags": RippleField(type=FIELD_TYPE_INT32, key=2), + "txnSignature": RippleField(type=FIELD_TYPE_VL, key=4), + "lastLedgerSequence": RippleField(type=FIELD_TYPE_INT32, key=27), + "destinationTag": RippleField(type=FIELD_TYPE_INT32, key=14), } TRANSACTION_TYPES = {"Payment": 0} -def serialize(msg: RippleSignTx, source_address: str, pubkey=None, signature=None): +def serialize( + msg: RippleSignTx, + source_address: str, + pubkey: bytes, + signature: bytes | None = None, +) -> bytearray: w = bytearray() # must be sorted numerically first by type and then by name write(w, FIELDS_MAP["type"], TRANSACTION_TYPES["Payment"]) @@ -52,31 +69,36 @@ def serialize(msg: RippleSignTx, source_address: str, pubkey=None, signature=Non return w -def write(w: bytearray, field: dict, value): +def write(w: Writer, field: RippleField, value: int | bytes | str | None) -> None: if value is None: return write_type(w, field) - if field["type"] == FIELD_TYPE_INT16: + if field.type == FIELD_TYPE_INT16: + assert isinstance(value, int) w.extend(value.to_bytes(2, "big")) - elif field["type"] == FIELD_TYPE_INT32: + elif field.type == FIELD_TYPE_INT32: + assert isinstance(value, int) w.extend(value.to_bytes(4, "big")) - elif field["type"] == FIELD_TYPE_AMOUNT: + elif field.type == FIELD_TYPE_AMOUNT: + assert isinstance(value, int) w.extend(serialize_amount(value)) - elif field["type"] == FIELD_TYPE_ACCOUNT: + elif field.type == FIELD_TYPE_ACCOUNT: + assert isinstance(value, str) write_bytes_varint(w, helpers.decode_address(value)) - elif field["type"] == FIELD_TYPE_VL: + elif field.type == FIELD_TYPE_VL: + assert isinstance(value, (bytes, bytearray)) write_bytes_varint(w, value) else: raise ValueError("Unknown field type") -def write_type(w: bytearray, field: dict): - if field["key"] <= 0xF: - w.append((field["type"] << 4) | field["key"]) +def write_type(w: Writer, field: RippleField) -> None: + if field.key <= 0xF: + w.append((field.type << 4) | field.key) else: # this concerns two-bytes fields such as lastLedgerSequence - w.append(field["type"] << 4) - w.append(field["key"]) + w.append(field.type << 4) + w.append(field.key) def serialize_amount(value: int) -> bytearray: @@ -91,13 +113,13 @@ def serialize_amount(value: int) -> bytearray: return b -def write_bytes_varint(w: bytearray, value: bytes): +def write_bytes_varint(w: Writer, value: bytes) -> None: """Serialize a variable length bytes.""" write_varint(w, len(value)) w.extend(value) -def write_varint(w: bytearray, val: int): +def write_varint(w: Writer, val: int) -> None: """ Implements variable-length int encoding from Ripple. See: https://ripple.com/wiki/Binary_Format#Variable_Length_Data_Encoding @@ -119,7 +141,7 @@ def write_varint(w: bytearray, val: int): raise ValueError("Value is too large") -def rshift(val, n): +def rshift(val: int, n: int) -> int: """ Implements signed right-shift. See: http://stackoverflow.com/a/5833119/15677 diff --git a/core/src/apps/ripple/sign_tx.py b/core/src/apps/ripple/sign_tx.py index 93ba7541c..88551cf1d 100644 --- a/core/src/apps/ripple/sign_tx.py +++ b/core/src/apps/ripple/sign_tx.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.crypto import der from trezor.crypto.curve import secp256k1 from trezor.crypto.hashlib import sha512 @@ -10,9 +12,15 @@ from apps.common.keychain import auto_keychain from . import helpers, layout from .serialize import serialize +if TYPE_CHECKING: + from apps.common.keychain import Keychain + from trezor.wire import Context + @auto_keychain(__name__) -async def sign_tx(ctx, msg: RippleSignTx, keychain): +async def sign_tx( + ctx: Context, msg: RippleSignTx, keychain: Keychain +) -> RippleSignedTx: validate(msg) await paths.validate_path(ctx, keychain, msg.address_n) @@ -34,17 +42,17 @@ async def sign_tx(ctx, msg: RippleSignTx, keychain): return RippleSignedTx(signature=signature, serialized_tx=tx) -def check_fee(fee: int): +def check_fee(fee: int) -> None: if fee < helpers.MIN_FEE or fee > helpers.MAX_FEE: raise ProcessError("Fee must be in the range of 10 to 10,000 drops") -def get_network_prefix(): +def get_network_prefix() -> bytes: """Network prefix is prepended before the transaction and public key is included""" return helpers.HASH_TX_SIGN.to_bytes(4, "big") -def first_half_of_sha512(b): +def first_half_of_sha512(b: bytes) -> bytes: """First half of SHA512, which Ripple uses""" hash = sha512(b) return hash.digest()[:32] @@ -57,26 +65,16 @@ def ecdsa_sign(private_key: bytes, digest: bytes) -> bytes: return sig_der -def set_canonical_flag(msg: RippleSignTx): +def set_canonical_flag(msg: RippleSignTx) -> None: """ Our ECDSA implementation already returns fully-canonical signatures, so we're enforcing it in the transaction using the designated flag - see https://wiki.ripple.com/Transaction_Malleability#Using_Fully-Canonical_Signatures - see https://github.com/trezor/trezor-crypto/blob/3e8974ff8871263a70b7fbb9a27a1da5b0d810f7/ecdsa.c#L791 """ - if msg.flags is None: - msg.flags = 0 msg.flags |= helpers.FLAG_FULLY_CANONICAL -def validate(msg: RippleSignTx): - if None in (msg.fee, msg.sequence, msg.payment) or ( - msg.payment and None in (msg.payment.amount, msg.payment.destination) - ): - raise ProcessError( - "Some of the required fields are missing (fee, sequence, payment.amount, payment.destination)" - ) - if msg.payment.amount < 0: - raise ProcessError("Only non-negative amounts are allowed.") +def validate(msg: RippleSignTx) -> None: if msg.payment.amount > helpers.MAX_ALLOWED_AMOUNT: raise ProcessError("Amount exceeds maximum allowed amount.") diff --git a/core/src/apps/stellar/consts.py b/core/src/apps/stellar/consts.py index 0a08476d0..786b864f5 100644 --- a/core/src/apps/stellar/consts.py +++ b/core/src/apps/stellar/consts.py @@ -1,8 +1,9 @@ from micropython import const +from typing import TYPE_CHECKING from trezor.enums import MessageType -if False: +if TYPE_CHECKING: from typing import Union from trezor import protobuf @@ -99,4 +100,5 @@ def get_op_code(msg: protobuf.MessageType) -> int: wire = msg.MESSAGE_WIRE_TYPE if wire not in op_codes: raise ValueError("Stellar: op code unknown") + assert isinstance(wire, int) return op_codes[wire] diff --git a/core/src/apps/stellar/get_address.py b/core/src/apps/stellar/get_address.py index e48224093..ec4d4ce41 100644 --- a/core/src/apps/stellar/get_address.py +++ b/core/src/apps/stellar/get_address.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.messages import StellarAddress, StellarGetAddress from trezor.ui.layouts import show_address @@ -6,7 +8,7 @@ from apps.common.keychain import auto_keychain from . import helpers -if False: +if TYPE_CHECKING: from trezor.wire import Context from apps.common.keychain import Keychain diff --git a/core/src/apps/stellar/layout.py b/core/src/apps/stellar/layout.py index 1d3004f40..955329b6e 100644 --- a/core/src/apps/stellar/layout.py +++ b/core/src/apps/stellar/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import strings, ui from trezor.enums import ButtonRequestType, StellarAssetType, StellarMemoType from trezor.ui.layouts import ( @@ -11,7 +13,7 @@ from trezor.wire import DataError from . import consts -if False: +if TYPE_CHECKING: from trezor.wire import Context from trezor.messages import StellarAsset diff --git a/core/src/apps/stellar/operations/__init__.py b/core/src/apps/stellar/operations/__init__.py index bf5c6b625..60315aa88 100644 --- a/core/src/apps/stellar/operations/__init__.py +++ b/core/src/apps/stellar/operations/__init__.py @@ -1,7 +1,9 @@ +from typing import TYPE_CHECKING + from .. import consts, writers from . import layout, serialize -if False: +if TYPE_CHECKING: from trezor.utils import Writer from trezor.wire import Context diff --git a/core/src/apps/stellar/operations/layout.py b/core/src/apps/stellar/operations/layout.py index a6f447f69..738a4e1af 100644 --- a/core/src/apps/stellar/operations/layout.py +++ b/core/src/apps/stellar/operations/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.enums import StellarAssetType, StellarSignerType from trezor.messages import ( StellarAccountMergeOp, @@ -29,7 +31,7 @@ from trezor.wire import DataError, ProcessError from .. import consts, helpers from ..layout import format_amount, format_asset -if False: +if TYPE_CHECKING: from trezor.wire import Context diff --git a/core/src/apps/stellar/operations/serialize.py b/core/src/apps/stellar/operations/serialize.py index d18fcb5b1..517c85ca1 100644 --- a/core/src/apps/stellar/operations/serialize.py +++ b/core/src/apps/stellar/operations/serialize.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor.enums import StellarAssetType from trezor.messages import ( StellarAccountMergeOp, @@ -19,7 +21,7 @@ from trezor.wire import DataError, ProcessError from .. import writers -if False: +if TYPE_CHECKING: from trezor.utils import Writer diff --git a/core/src/apps/stellar/sign_tx.py b/core/src/apps/stellar/sign_tx.py index df20e43c0..19d934fb2 100644 --- a/core/src/apps/stellar/sign_tx.py +++ b/core/src/apps/stellar/sign_tx.py @@ -1,3 +1,4 @@ +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor.crypto.curve import ed25519 @@ -12,8 +13,9 @@ from apps.common.keychain import auto_keychain from . import consts, helpers, layout, writers from .operations import process_operation -if False: +if TYPE_CHECKING: from trezor.wire import Context + from trezor.utils import Writer from apps.common.keychain import Keychain @@ -45,14 +47,14 @@ async def sign_tx( return StellarSignedTx(public_key=pubkey, signature=signature) -async def _final(ctx: Context, w: bytearray, msg: StellarSignTx) -> None: +async def _final(ctx: Context, w: Writer, msg: StellarSignTx) -> None: # 4 null bytes representing a (currently unused) empty union writers.write_uint32(w, 0) # final confirm await layout.require_confirm_final(ctx, msg.fee, msg.num_operations) -async def _init(ctx: Context, w: bytearray, pubkey: bytes, msg: StellarSignTx) -> None: +async def _init(ctx: Context, w: Writer, pubkey: bytes, msg: StellarSignTx) -> None: network_passphrase_hash = sha256(msg.network_passphrase.encode()).digest() writers.write_bytes_fixed(w, network_passphrase_hash, 32) writers.write_bytes_fixed(w, consts.TX_TYPE, 4) @@ -70,7 +72,7 @@ async def _init(ctx: Context, w: bytearray, pubkey: bytes, msg: StellarSignTx) - ) -async def _timebounds(ctx: Context, w: bytearray, start: int, end: int) -> None: +async def _timebounds(ctx: Context, w: Writer, start: int, end: int) -> None: # confirm dialog await layout.require_confirm_timebounds(ctx, start, end) @@ -80,14 +82,14 @@ async def _timebounds(ctx: Context, w: bytearray, start: int, end: int) -> None: writers.write_uint64(w, end) -async def _operations(ctx: Context, w: bytearray, num_operations: int) -> None: +async def _operations(ctx: Context, w: Writer, num_operations: int) -> None: writers.write_uint32(w, num_operations) for _ in range(num_operations): op = await ctx.call_any(StellarTxOpRequest(), *consts.op_wire_types) await process_operation(ctx, w, op) # type: ignore -async def _memo(ctx: Context, w: bytearray, msg: StellarSignTx) -> None: +async def _memo(ctx: Context, w: Writer, msg: StellarSignTx) -> None: writers.write_uint32(w, msg.memo_type) if msg.memo_type == StellarMemoType.NONE: # nothing is serialized diff --git a/core/src/apps/stellar/writers.py b/core/src/apps/stellar/writers.py index 064671c36..f57538eba 100644 --- a/core/src/apps/stellar/writers.py +++ b/core/src/apps/stellar/writers.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from apps.common.writers import ( write_bytes_fixed, write_bytes_unchecked, @@ -10,7 +12,7 @@ from .helpers import public_key_from_address write_uint32 = write_uint32_be write_uint64 = write_uint64_be -if False: +if TYPE_CHECKING: from typing import AnyStr from trezor.utils import Writer diff --git a/core/src/apps/tezos/get_address.py b/core/src/apps/tezos/get_address.py index 4b16cab54..040318978 100644 --- a/core/src/apps/tezos/get_address.py +++ b/core/src/apps/tezos/get_address.py @@ -1,5 +1,7 @@ +from typing import TYPE_CHECKING + from trezor.crypto import hashlib -from trezor.messages import TezosAddress +from trezor.messages import TezosAddress, TezosGetAddress from trezor.ui.layouts import show_address from apps.common import paths, seed @@ -7,9 +9,15 @@ from apps.common.keychain import with_slip44_keychain from . import CURVE, PATTERNS, SLIP44_ID, helpers +if TYPE_CHECKING: + from apps.common.keychain import Keychain + from trezor.wire import Context + @with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) -async def get_address(ctx, msg, keychain): +async def get_address( + ctx: Context, msg: TezosGetAddress, keychain: Keychain +) -> TezosAddress: await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) diff --git a/core/src/apps/tezos/get_public_key.py b/core/src/apps/tezos/get_public_key.py index 87288ef06..be36c710b 100644 --- a/core/src/apps/tezos/get_public_key.py +++ b/core/src/apps/tezos/get_public_key.py @@ -1,4 +1,6 @@ -from trezor.messages import TezosPublicKey +from typing import TYPE_CHECKING + +from trezor.messages import TezosGetPublicKey, TezosPublicKey from trezor.ui.layouts import show_pubkey from apps.common import paths, seed @@ -6,9 +8,15 @@ from apps.common.keychain import with_slip44_keychain from . import CURVE, PATTERNS, SLIP44_ID, helpers +if TYPE_CHECKING: + from apps.common.keychain import Keychain + from trezor.wire import Context + @with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) -async def get_public_key(ctx, msg, keychain): +async def get_public_key( + ctx: Context, msg: TezosGetPublicKey, keychain: Keychain +) -> TezosPublicKey: await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) diff --git a/core/src/apps/tezos/helpers.py b/core/src/apps/tezos/helpers.py index 93f80a44f..4e8df5607 100644 --- a/core/src/apps/tezos/helpers.py +++ b/core/src/apps/tezos/helpers.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import wire from trezor.crypto import base58 @@ -7,6 +8,10 @@ from trezor.utils import BufferReader, ensure from apps.common.readers import read_uint32_be from apps.common.writers import write_bytes_unchecked, write_uint8 +if TYPE_CHECKING: + from trezor.utils import Writer + + TEZOS_AMOUNT_DECIMALS = const(6) TEZOS_ED25519_ADDRESS_PREFIX = "tz1" TEZOS_ORIGINATED_ADDRESS_PREFIX = "KT1" @@ -82,28 +87,28 @@ OP_TAG_DELEGATION = const(110) EP_TAG_NAMED = const(255) -def base58_encode_check(payload, prefix=None): +def base58_encode_check(payload: bytes, prefix: str | None = None) -> str: result = payload if prefix is not None: result = TEZOS_PREFIX_BYTES[prefix] + payload return base58.encode_check(result) -def base58_decode_check(enc, prefix=None): +def base58_decode_check(enc: str, prefix: str | None = None) -> bytes: decoded = base58.decode_check(enc) if prefix is not None: decoded = decoded[len(TEZOS_PREFIX_BYTES[prefix]) :] return decoded -def write_bool(w: bytearray, boolean: bool): +def write_bool(w: Writer, boolean: bool) -> None: if boolean: write_uint8(w, 255) else: write_uint8(w, 0) -def write_instruction(w: bytearray, instruction: str) -> int: +def write_instruction(w: Writer, instruction: str) -> None: write_bytes_unchecked(w, MICHELSON_INSTRUCTION_BYTES[instruction]) diff --git a/core/src/apps/tezos/layout.py b/core/src/apps/tezos/layout.py index a1ca1f4b2..39ca4cce6 100644 --- a/core/src/apps/tezos/layout.py +++ b/core/src/apps/tezos/layout.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui from trezor.enums import ButtonRequestType from trezor.strings import format_amount @@ -11,8 +13,11 @@ from trezor.ui.layouts import ( from .helpers import TEZOS_AMOUNT_DECIMALS +if TYPE_CHECKING: + from trezor.wire import Context + -async def require_confirm_tx(ctx, to, value): +async def require_confirm_tx(ctx: Context, to: str, value: int) -> None: await confirm_output( ctx, to, @@ -24,7 +29,7 @@ async def require_confirm_tx(ctx, to, value): ) -async def require_confirm_fee(ctx, value, fee): +async def require_confirm_fee(ctx: Context, value: int, fee: int) -> None: await confirm_total( ctx, total_amount=format_tezos_amount(value), @@ -34,7 +39,7 @@ async def require_confirm_fee(ctx, value, fee): ) -async def require_confirm_origination(ctx, address): +async def require_confirm_origination(ctx: Context, address: str) -> None: await confirm_address( ctx, title="Confirm origination", @@ -46,7 +51,7 @@ async def require_confirm_origination(ctx, address): ) -async def require_confirm_origination_fee(ctx, balance, fee): +async def require_confirm_origination_fee(ctx: Context, balance: int, fee: int) -> None: await confirm_properties( ctx, title="Confirm origination", @@ -60,7 +65,7 @@ async def require_confirm_origination_fee(ctx, balance, fee): ) -async def require_confirm_delegation_baker(ctx, baker): +async def require_confirm_delegation_baker(ctx: Context, baker: str) -> None: await confirm_address( ctx, title="Confirm delegation", @@ -72,7 +77,7 @@ async def require_confirm_delegation_baker(ctx, baker): ) -async def require_confirm_set_delegate(ctx, fee): +async def require_confirm_set_delegate(ctx: Context, fee: int) -> None: await confirm_metadata( ctx, "confirm_delegation_final", @@ -86,7 +91,9 @@ async def require_confirm_set_delegate(ctx, fee): ) -async def require_confirm_register_delegate(ctx, address, fee): +async def require_confirm_register_delegate( + ctx: Context, address: str, fee: int +) -> None: await confirm_properties( ctx, "confirm_register_delegate", @@ -100,12 +107,12 @@ async def require_confirm_register_delegate(ctx, address, fee): ) -def format_tezos_amount(value): +def format_tezos_amount(value: int) -> str: formatted_value = format_amount(value, TEZOS_AMOUNT_DECIMALS) return formatted_value + " XTZ" -async def require_confirm_ballot(ctx, proposal, ballot): +async def require_confirm_ballot(ctx: Context, proposal: str, ballot: str) -> None: await confirm_properties( ctx, "confirm_ballot", @@ -119,7 +126,7 @@ async def require_confirm_ballot(ctx, proposal, ballot): ) -async def require_confirm_proposals(ctx, proposals): +async def require_confirm_proposals(ctx: Context, proposals: list[str]) -> None: if len(proposals) > 1: title = "Submit proposals" else: @@ -137,7 +144,9 @@ async def require_confirm_proposals(ctx, proposals): ) -async def require_confirm_delegation_manager_withdraw(ctx, address): +async def require_confirm_delegation_manager_withdraw( + ctx: Context, address: str +) -> None: await confirm_address( ctx, title="Remove delegation", @@ -150,7 +159,7 @@ async def require_confirm_delegation_manager_withdraw(ctx, address): ) -async def require_confirm_manager_remove_delegate(ctx, fee): +async def require_confirm_manager_remove_delegate(ctx: Context, fee: int) -> None: await confirm_metadata( ctx, "confirm_undelegation_final", diff --git a/core/src/apps/tezos/sign_tx.py b/core/src/apps/tezos/sign_tx.py index 829a4bbb8..d7493b4fe 100644 --- a/core/src/apps/tezos/sign_tx.py +++ b/core/src/apps/tezos/sign_tx.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import wire from trezor.crypto import hashlib from trezor.crypto.curve import ed25519 @@ -15,9 +17,26 @@ from apps.common.writers import ( from . import CURVE, PATTERNS, SLIP44_ID, helpers, layout +if TYPE_CHECKING: + from typing import Union + from apps.common.keychain import Keychain + from trezor.wire import Context + from trezor.messages import ( + TezosSignTx, + TezosContractID, + TezosManagerTransfer, + TezosBallotOp, + TezosProposalOp, + TezosRevealOp, + TezosDelegationOp, + TezosTransactionOp, + TezosOriginationOp, + ) + from trezor.utils import Writer + @with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE) -async def sign_tx(ctx, msg, keychain): +async def sign_tx(ctx: Context, msg: TezosSignTx, keychain: Keychain) -> TezosSignedTx: await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) @@ -74,12 +93,12 @@ async def sign_tx(ctx, msg, keychain): elif msg.delegation is not None: source = _get_address_by_tag(msg.delegation.source) - delegate = None + delegate_address: str | None = None if msg.delegation.delegate is not None: - delegate = _get_address_by_tag(msg.delegation.delegate) + delegate_address = _get_address_by_tag(msg.delegation.delegate) - if delegate is not None and source != delegate: - await layout.require_confirm_delegation_baker(ctx, delegate) + if delegate_address is not None and source != delegate_address: + await layout.require_confirm_delegation_baker(ctx, delegate_address) await layout.require_confirm_set_delegate(ctx, msg.delegation.fee) # if account registers itself as a delegate else: @@ -124,7 +143,7 @@ async def sign_tx(ctx, msg, keychain): ) -def _get_address_by_tag(address_hash): +def _get_address_by_tag(address_hash: bytes) -> str: prefixes = ["tz1", "tz2", "tz3"] tag = int(address_hash[0]) @@ -133,7 +152,7 @@ def _get_address_by_tag(address_hash): raise wire.DataError("Invalid tag in address hash") -def _get_address_from_contract(address): +def _get_address_from_contract(address: TezosContractID) -> str: if address.tag == TezosContractType.Implicit: return _get_address_by_tag(address.hash) @@ -145,11 +164,11 @@ def _get_address_from_contract(address): raise wire.DataError("Invalid contract type") -def _get_protocol_hash(proposal): +def _get_protocol_hash(proposal: bytes) -> str: return helpers.base58_encode_check(proposal, prefix="P") -def _get_ballot(ballot): +def _get_ballot(ballot: TezosBallotType) -> str: if ballot == TezosBallotType.Yay: return "yay" elif ballot == TezosBallotType.Nay: @@ -160,7 +179,7 @@ def _get_ballot(ballot): raise RuntimeError # unrecognized enum value -def _get_operation_bytes(w: bytearray, msg): +def _get_operation_bytes(w: Writer, msg: TezosSignTx) -> None: write_bytes_fixed(w, msg.branch, helpers.BRANCH_HASH_SIZE) # when the account sends first operation in lifetime, @@ -191,6 +210,7 @@ def _get_operation_bytes(w: bytearray, msg): elif parameters_manager.cancel_delegate is not None: _encode_manager_delegation_remove(w) elif parameters_manager.transfer is not None: + assert parameters_manager.transfer.destination is not None if ( parameters_manager.transfer.destination.tag == TezosContractType.Implicit @@ -227,7 +247,13 @@ def _get_operation_bytes(w: bytearray, msg): _encode_ballot(w, msg.ballot) -def _encode_common(w: bytearray, operation, str_operation): +def _encode_common( + w: Writer, + operation: Union[ + TezosDelegationOp, TezosOriginationOp, TezosTransactionOp, TezosRevealOp + ], + str_operation: str, +) -> None: operation_tags = { "reveal": helpers.OP_TAG_REVEAL, "transaction": helpers.OP_TAG_TRANSACTION, @@ -242,12 +268,14 @@ def _encode_common(w: bytearray, operation, str_operation): _encode_zarith(w, operation.storage_limit) -def _encode_contract_id(w: bytearray, contract_id): +def _encode_contract_id(w: Writer, contract_id: TezosContractID) -> None: write_uint8(w, contract_id.tag) write_bytes_fixed(w, contract_id.hash, helpers.CONTRACT_ID_SIZE - 1) -def _encode_data_with_bool_prefix(w: bytearray, data: bytes, expected_length: int): +def _encode_data_with_bool_prefix( + w: Writer, data: bytes | None, expected_length: int +) -> None: if data: helpers.write_bool(w, True) write_bytes_fixed(w, data, expected_length) @@ -255,7 +283,7 @@ def _encode_data_with_bool_prefix(w: bytearray, data: bytes, expected_length: in helpers.write_bool(w, False) -def _encode_zarith(w: bytearray, num): +def _encode_zarith(w: Writer, num: int) -> None: while True: byte = num & 127 num = num >> 7 @@ -267,7 +295,7 @@ def _encode_zarith(w: bytearray, num): write_uint8(w, 128 | byte) -def _encode_proposal(w: bytearray, proposal): +def _encode_proposal(w: Writer, proposal: TezosProposalOp) -> None: write_uint8(w, helpers.OP_TAG_PROPOSALS) write_bytes_fixed(w, proposal.source, helpers.TAGGED_PUBKEY_HASH_SIZE) write_uint32_be(w, proposal.period) @@ -276,7 +304,7 @@ def _encode_proposal(w: bytearray, proposal): write_bytes_fixed(w, proposal_hash, helpers.PROPOSAL_HASH_SIZE) -def _encode_ballot(w: bytearray, ballot): +def _encode_ballot(w: Writer, ballot: TezosBallotOp) -> None: write_uint8(w, helpers.OP_TAG_BALLOT) write_bytes_fixed(w, ballot.source, helpers.TAGGED_PUBKEY_HASH_SIZE) write_uint32_be(w, ballot.period) @@ -284,7 +312,7 @@ def _encode_ballot(w: bytearray, ballot): write_uint8(w, ballot.ballot) -def _encode_natural(w: bytearray, num): +def _encode_natural(w: Writer, num: int) -> None: # encode a natural integer with its signed bit on position 7 # as we do not expect negative numbers in a transfer operation the bit is never set natural_tag = 0 @@ -300,7 +328,9 @@ def _encode_natural(w: bytearray, num): _encode_zarith(w, modified) -def _encode_manager_common(w: bytearray, sequence_length, operation, to_contract=False): +def _encode_manager_common( + w: Writer, sequence_length: int, operation: str, to_contract: bool = False +) -> None: # 5 = tag and sequence_length (1 byte + 4 bytes) argument_length = sequence_length + 5 @@ -313,19 +343,21 @@ def _encode_manager_common(w: bytearray, sequence_length, operation, to_contract helpers.write_instruction(w, "NIL") helpers.write_instruction(w, "operation") helpers.write_instruction(w, operation) - if to_contract is True: + if to_contract: helpers.write_instruction(w, "address") else: helpers.write_instruction(w, "key_hash") if operation == "PUSH": write_uint8(w, 10) # byte sequence - if to_contract is True: + if to_contract: write_uint32_be(w, helpers.CONTRACT_ID_SIZE) else: write_uint32_be(w, helpers.TAGGED_PUBKEY_HASH_SIZE) -def _encode_manager_to_implicit_transfer(w: bytearray, manager_transfer): +def _encode_manager_to_implicit_transfer( + w: Writer, manager_transfer: TezosManagerTransfer +) -> None: MICHELSON_LENGTH = 48 value_natural = bytearray() @@ -346,7 +378,7 @@ def _encode_manager_to_implicit_transfer(w: bytearray, manager_transfer): # smart_contract_delegation -def _encode_manager_delegation(w: bytearray, delegate): +def _encode_manager_delegation(w: Writer, delegate: bytes) -> None: MICHELSON_LENGTH = 42 # length is fixed this time(no variable length fields) _encode_manager_common(w, MICHELSON_LENGTH, "PUSH") @@ -356,14 +388,16 @@ def _encode_manager_delegation(w: bytearray, delegate): helpers.write_instruction(w, "CONS") -def _encode_manager_delegation_remove(w: bytearray): +def _encode_manager_delegation_remove(w: Writer) -> None: MICHELSON_LENGTH = 14 # length is fixed this time(no variable length fields) _encode_manager_common(w, MICHELSON_LENGTH, "NONE") helpers.write_instruction(w, "SET_DELEGATE") helpers.write_instruction(w, "CONS") -def _encode_manager_to_manager_transfer(w: bytearray, manager_transfer): +def _encode_manager_to_manager_transfer( + w: Writer, manager_transfer: TezosManagerTransfer +) -> None: MICHELSON_LENGTH = 77 value_natural = bytearray() diff --git a/core/src/apps/webauthn/credential.py b/core/src/apps/webauthn/credential.py index fb196ca99..1bb627a7e 100644 --- a/core/src/apps/webauthn/credential.py +++ b/core/src/apps/webauthn/credential.py @@ -1,5 +1,6 @@ import ustruct from micropython import const +from typing import Iterable from ubinascii import hexlify import storage.device @@ -12,9 +13,6 @@ from apps.common.paths import HARDENED from . import common -if False: - from typing import Iterable - # Credential ID values _CRED_ID_VERSION = b"\xf1\xd0\x02\x00" CRED_ID_MIN_LENGTH = const(33) diff --git a/core/src/apps/webauthn/fido2.py b/core/src/apps/webauthn/fido2.py index 8526def7f..88146b49e 100644 --- a/core/src/apps/webauthn/fido2.py +++ b/core/src/apps/webauthn/fido2.py @@ -2,6 +2,7 @@ import uctypes import ustruct import utime from micropython import const +from typing import Any, Callable, Coroutine, Iterable, Iterator import storage import storage.resident_credentials @@ -21,15 +22,6 @@ from . import common from .credential import CRED_ID_MAX_LENGTH, Credential, Fido2Credential, U2fCredential from .resident_credentials import find_by_rp_id_hash, store_resident_credential -if False: - from typing import ( - Any, - Callable, - Coroutine, - Iterable, - Iterator, - ) - _CID_BROADCAST = const(0xFFFF_FFFF) # broadcast channel id # types of frame @@ -234,7 +226,7 @@ class CborError(Exception): self.code = code -def frame_init() -> dict: +def frame_init() -> uctypes.StructDict: # uint32_t cid; // Channel identifier # uint8_t cmd; // Command - b7 set # uint8_t bcnth; // Message byte count - high part @@ -248,7 +240,7 @@ def frame_init() -> dict: } -def frame_cont() -> dict: +def frame_cont() -> uctypes.StructDict: # uint32_t cid; // Channel identifier # uint8_t seq; // Sequence number - b7 cleared # uint8_t data[HID_RPT_SIZE - 5]; // Data payload @@ -259,7 +251,7 @@ def frame_cont() -> dict: } -def resp_cmd_init() -> dict: +def resp_cmd_init() -> uctypes.StructDict: # uint8_t nonce[8]; // Client application nonce # uint32_t cid; // Channel identifier # uint8_t versionInterface; // Interface version @@ -304,7 +296,7 @@ def resp_cmd_register(khlen: int, certlen: int, siglen: int) -> dict: _REQ_CMD_AUTHENTICATE_KHLEN = const(64) -def req_cmd_authenticate(khlen: int) -> dict: +def req_cmd_authenticate(khlen: int) -> uctypes.StructDict: # uint8_t chal[32]; // Challenge # uint8_t appId[32]; // Application id # uint8_t keyHandleLen; // Length of key handle @@ -317,7 +309,7 @@ def req_cmd_authenticate(khlen: int) -> dict: } -def resp_cmd_authenticate(siglen: int) -> dict: +def resp_cmd_authenticate(siglen: int) -> uctypes.StructDict: status_ofs = 5 + siglen # uint8_t flags; // U2F_AUTH_FLAG_ values # uint32_t ctr; // Counter field (big-endian) @@ -331,15 +323,15 @@ def resp_cmd_authenticate(siglen: int) -> dict: } -def overlay_struct(buf: bytearray, desc: dict) -> Any: - desc_size = uctypes.sizeof(desc, uctypes.BIG_ENDIAN) # type: ignore +def overlay_struct(buf: bytearray, desc: uctypes.StructDict) -> Any: + desc_size = uctypes.sizeof(desc, uctypes.BIG_ENDIAN) if desc_size > len(buf): raise ValueError(f"desc is too big ({desc_size} > {len(buf)})") return uctypes.struct(uctypes.addressof(buf), desc, uctypes.BIG_ENDIAN) -def make_struct(desc: dict) -> tuple[bytearray, Any]: - desc_size = uctypes.sizeof(desc, uctypes.BIG_ENDIAN) # type: ignore +def make_struct(desc: uctypes.StructDict) -> tuple[bytearray, Any]: + desc_size = uctypes.sizeof(desc, uctypes.BIG_ENDIAN) buf = bytearray(desc_size) return buf, uctypes.struct(uctypes.addressof(buf), desc, uctypes.BIG_ENDIAN) @@ -605,7 +597,7 @@ class State: raise NotImplementedError async def confirm_dialog(self) -> bool | "State": - pass + raise NotImplementedError async def on_confirm(self) -> None: pass @@ -1647,6 +1639,7 @@ def cbor_get_assertion_process(req: Cmd, dialog_mgr: DialogManager) -> State | C rp_id_hash = hashlib.sha256(rp_id).digest() allow_list = param.get(_GETASSERT_CMD_ALLOW_LIST, []) + cred_list: list[Credential] if allow_list: # Get all credentials from the allow list that belong to this authenticator. allowed_creds = credentials_from_descriptor_list(allow_list, rp_id_hash) diff --git a/core/src/apps/webauthn/resident_credentials.py b/core/src/apps/webauthn/resident_credentials.py index a7466f9a5..eda12d86c 100644 --- a/core/src/apps/webauthn/resident_credentials.py +++ b/core/src/apps/webauthn/resident_credentials.py @@ -1,14 +1,11 @@ from micropython import const +from typing import Iterator import storage.resident_credentials from storage.resident_credentials import MAX_RESIDENT_CREDENTIALS from .credential import Fido2Credential -if False: - from typing import Iterator - - RP_ID_HASH_LENGTH = const(32) diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py index 5da5ec432..987866afc 100644 --- a/core/src/apps/workflow_handlers.py +++ b/core/src/apps/workflow_handlers.py @@ -1,15 +1,17 @@ +from typing import TYPE_CHECKING + from trezor import utils from trezor.enums import MessageType -if False: - from trezor.wire import Handler +if TYPE_CHECKING: + from trezor.wire import Handler, Msg from trezorio import WireInterface workflow_handlers: dict[int, Handler] = {} -def register(wire_type: int, handler: Handler) -> None: +def register(wire_type: int, handler: Handler[Msg]) -> None: """Register `handler` to get scheduled after `wire_type` message is received.""" workflow_handlers[wire_type] = handler @@ -24,159 +26,153 @@ def find_message_handler_module(msg_type: int) -> str: - collecting everything as strings instead of importing directly means that we don't need to load any of the modules into memory until we actually need them """ - if False: - raise RuntimeError - # debug - elif __debug__ and msg_type == MessageType.LoadDevice: + if __debug__ and msg_type == MessageType.LoadDevice: return "apps.debug.load_device" # management - elif msg_type == MessageType.ResetDevice: + if msg_type == MessageType.ResetDevice: return "apps.management.reset_device" - elif msg_type == MessageType.BackupDevice: + if msg_type == MessageType.BackupDevice: return "apps.management.backup_device" - elif msg_type == MessageType.WipeDevice: + if msg_type == MessageType.WipeDevice: return "apps.management.wipe_device" - elif msg_type == MessageType.RecoveryDevice: + if msg_type == MessageType.RecoveryDevice: return "apps.management.recovery_device" - elif msg_type == MessageType.ApplySettings: + if msg_type == MessageType.ApplySettings: return "apps.management.apply_settings" - elif msg_type == MessageType.ApplyFlags: + if msg_type == MessageType.ApplyFlags: return "apps.management.apply_flags" - elif msg_type == MessageType.ChangePin: + if msg_type == MessageType.ChangePin: return "apps.management.change_pin" - elif msg_type == MessageType.ChangeWipeCode: + if msg_type == MessageType.ChangeWipeCode: return "apps.management.change_wipe_code" - elif utils.MODEL == "T" and msg_type == MessageType.SdProtect: + if utils.MODEL == "T" and msg_type == MessageType.SdProtect: return "apps.management.sd_protect" # bitcoin - elif msg_type == MessageType.AuthorizeCoinJoin: + if msg_type == MessageType.AuthorizeCoinJoin: return "apps.bitcoin.authorize_coinjoin" - elif msg_type == MessageType.GetPublicKey: + if msg_type == MessageType.GetPublicKey: return "apps.bitcoin.get_public_key" - elif msg_type == MessageType.GetAddress: + if msg_type == MessageType.GetAddress: return "apps.bitcoin.get_address" - elif msg_type == MessageType.GetOwnershipId: + if msg_type == MessageType.GetOwnershipId: return "apps.bitcoin.get_ownership_id" - elif msg_type == MessageType.GetOwnershipProof: + if msg_type == MessageType.GetOwnershipProof: return "apps.bitcoin.get_ownership_proof" - elif msg_type == MessageType.SignTx: + if msg_type == MessageType.SignTx: return "apps.bitcoin.sign_tx" - elif msg_type == MessageType.SignMessage: + if msg_type == MessageType.SignMessage: return "apps.bitcoin.sign_message" - elif msg_type == MessageType.VerifyMessage: + if msg_type == MessageType.VerifyMessage: return "apps.bitcoin.verify_message" # misc - elif msg_type == MessageType.GetEntropy: + if msg_type == MessageType.GetEntropy: return "apps.misc.get_entropy" - elif msg_type == MessageType.SignIdentity: + if msg_type == MessageType.SignIdentity: return "apps.misc.sign_identity" - elif msg_type == MessageType.GetECDHSessionKey: + if msg_type == MessageType.GetECDHSessionKey: return "apps.misc.get_ecdh_session_key" - elif msg_type == MessageType.CipherKeyValue: + if msg_type == MessageType.CipherKeyValue: return "apps.misc.cipher_key_value" - elif not utils.BITCOIN_ONLY: - if False: - raise RuntimeError - - elif msg_type == MessageType.SetU2FCounter: + if not utils.BITCOIN_ONLY: + if msg_type == MessageType.SetU2FCounter: return "apps.management.set_u2f_counter" - elif msg_type == MessageType.GetNextU2FCounter: + if msg_type == MessageType.GetNextU2FCounter: return "apps.management.get_next_u2f_counter" # webauthn - elif msg_type == MessageType.WebAuthnListResidentCredentials: + if msg_type == MessageType.WebAuthnListResidentCredentials: return "apps.webauthn.list_resident_credentials" - elif msg_type == MessageType.WebAuthnAddResidentCredential: + if msg_type == MessageType.WebAuthnAddResidentCredential: return "apps.webauthn.add_resident_credential" - elif msg_type == MessageType.WebAuthnRemoveResidentCredential: + if msg_type == MessageType.WebAuthnRemoveResidentCredential: return "apps.webauthn.remove_resident_credential" # ethereum - elif msg_type == MessageType.EthereumGetAddress: + if msg_type == MessageType.EthereumGetAddress: return "apps.ethereum.get_address" - elif msg_type == MessageType.EthereumGetPublicKey: + if msg_type == MessageType.EthereumGetPublicKey: return "apps.ethereum.get_public_key" - elif msg_type == MessageType.EthereumSignTx: + if msg_type == MessageType.EthereumSignTx: return "apps.ethereum.sign_tx" - elif msg_type == MessageType.EthereumSignTxEIP1559: + if msg_type == MessageType.EthereumSignTxEIP1559: return "apps.ethereum.sign_tx_eip1559" - elif msg_type == MessageType.EthereumSignMessage: + if msg_type == MessageType.EthereumSignMessage: return "apps.ethereum.sign_message" - elif msg_type == MessageType.EthereumVerifyMessage: + if msg_type == MessageType.EthereumVerifyMessage: return "apps.ethereum.verify_message" - elif msg_type == MessageType.EthereumSignTypedData: + if msg_type == MessageType.EthereumSignTypedData: return "apps.ethereum.sign_typed_data" # monero - elif msg_type == MessageType.MoneroGetAddress: + if msg_type == MessageType.MoneroGetAddress: return "apps.monero.get_address" - elif msg_type == MessageType.MoneroGetWatchKey: + if msg_type == MessageType.MoneroGetWatchKey: return "apps.monero.get_watch_only" - elif msg_type == MessageType.MoneroTransactionInitRequest: + if msg_type == MessageType.MoneroTransactionInitRequest: return "apps.monero.sign_tx" - elif msg_type == MessageType.MoneroKeyImageExportInitRequest: + if msg_type == MessageType.MoneroKeyImageExportInitRequest: return "apps.monero.key_image_sync" - elif msg_type == MessageType.MoneroGetTxKeyRequest: + if msg_type == MessageType.MoneroGetTxKeyRequest: return "apps.monero.get_tx_keys" - elif msg_type == MessageType.MoneroLiveRefreshStartRequest: + if msg_type == MessageType.MoneroLiveRefreshStartRequest: return "apps.monero.live_refresh" if __debug__ and msg_type == MessageType.DebugMoneroDiagRequest: return "apps.monero.diag" # nem - elif msg_type == MessageType.NEMGetAddress: + if msg_type == MessageType.NEMGetAddress: return "apps.nem.get_address" - elif msg_type == MessageType.NEMSignTx: + if msg_type == MessageType.NEMSignTx: return "apps.nem.sign_tx" # stellar - elif msg_type == MessageType.StellarGetAddress: + if msg_type == MessageType.StellarGetAddress: return "apps.stellar.get_address" - elif msg_type == MessageType.StellarSignTx: + if msg_type == MessageType.StellarSignTx: return "apps.stellar.sign_tx" # ripple - elif msg_type == MessageType.RippleGetAddress: + if msg_type == MessageType.RippleGetAddress: return "apps.ripple.get_address" - elif msg_type == MessageType.RippleSignTx: + if msg_type == MessageType.RippleSignTx: return "apps.ripple.sign_tx" # cardano - elif msg_type == MessageType.CardanoGetAddress: + if msg_type == MessageType.CardanoGetAddress: return "apps.cardano.get_address" - elif msg_type == MessageType.CardanoGetPublicKey: + if msg_type == MessageType.CardanoGetPublicKey: return "apps.cardano.get_public_key" - elif msg_type == MessageType.CardanoSignTxInit: + if msg_type == MessageType.CardanoSignTxInit: return "apps.cardano.sign_tx" - elif msg_type == MessageType.CardanoGetNativeScriptHash: + if msg_type == MessageType.CardanoGetNativeScriptHash: return "apps.cardano.get_native_script_hash" # tezos - elif msg_type == MessageType.TezosGetAddress: + if msg_type == MessageType.TezosGetAddress: return "apps.tezos.get_address" - elif msg_type == MessageType.TezosSignTx: + if msg_type == MessageType.TezosSignTx: return "apps.tezos.sign_tx" - elif msg_type == MessageType.TezosGetPublicKey: + if msg_type == MessageType.TezosGetPublicKey: return "apps.tezos.get_public_key" # eos - elif msg_type == MessageType.EosGetPublicKey: + if msg_type == MessageType.EosGetPublicKey: return "apps.eos.get_public_key" - elif msg_type == MessageType.EosSignTx: + if msg_type == MessageType.EosSignTx: return "apps.eos.sign_tx" # binance - elif msg_type == MessageType.BinanceGetAddress: + if msg_type == MessageType.BinanceGetAddress: return "apps.binance.get_address" - elif msg_type == MessageType.BinanceGetPublicKey: + if msg_type == MessageType.BinanceGetPublicKey: return "apps.binance.get_public_key" - elif msg_type == MessageType.BinanceSignTx: + if msg_type == MessageType.BinanceSignTx: return "apps.binance.sign_tx" raise ValueError diff --git a/core/src/storage/cache.py b/core/src/storage/cache.py index 91a93e1d0..f3225e731 100644 --- a/core/src/storage/cache.py +++ b/core/src/storage/cache.py @@ -1,18 +1,14 @@ import gc from trezorcrypto import random # avoid pulling in trezor.crypto +from typing import TYPE_CHECKING from trezor import utils -if False: +if TYPE_CHECKING: from typing import Sequence, TypeVar, overload T = TypeVar("T") -else: - - def overload(f) -> None: # type: ignore - pass - _MAX_SESSIONS_COUNT = 10 _SESSIONLESS_FLAG = 128 @@ -62,13 +58,15 @@ class DataCache: self.data[key][0] = 1 self.data[key][1:] = value - @overload - def get(self, key: int) -> bytes | None: - ... + if TYPE_CHECKING: - @overload - def get(self, key: int, default: T) -> bytes | T: # noqa: F811 - ... + @overload + def get(self, key: int) -> bytes | None: + ... + + @overload + def get(self, key: int, default: T) -> bytes | T: # noqa: F811 + ... def get(self, key: int, default: T | None = None) -> bytes | T | None: # noqa: F811 utils.ensure(key < len(self.fields)) @@ -223,14 +221,15 @@ def set(key: int, value: bytes) -> None: _SESSIONS[_active_session_idx].set(key, value) -@overload -def get(key: int) -> bytes | None: - ... +if TYPE_CHECKING: + @overload + def get(key: int) -> bytes | None: + ... -@overload -def get(key: int, default: T) -> bytes | T: # noqa: F811 - ... + @overload + def get(key: int, default: T) -> bytes | T: # noqa: F811 + ... def get(key: int, default: T | None = None) -> bytes | T | None: # noqa: F811 @@ -257,47 +256,38 @@ def delete(key: int) -> None: return _SESSIONS[_active_session_idx].delete(key) -if False: - from typing import Awaitable, Callable, TypeVar - - ByteFunc = TypeVar("ByteFunc", bound=Callable[..., bytes]) - AsyncByteFunc = TypeVar("AsyncByteFunc", bound=Callable[..., Awaitable[bytes]]) +if TYPE_CHECKING: + from typing import Awaitable, Callable, TypeVar, ParamSpec + P = ParamSpec("P") + ByteFunc = Callable[P, bytes] + AsyncByteFunc = Callable[P, Awaitable[bytes]] -def stored(key: int) -> Callable[[ByteFunc], ByteFunc]: - def decorator(func: ByteFunc) -> ByteFunc: - # if we didn't check this, it would be easy to store an Awaitable[something] - # in cache, which might prove hard to debug - # XXX mypy should be checking this now, but we don't have full coverage yet - assert not isinstance(func, type(lambda: (yield))), "use stored_async instead" - def wrapper(*args, **kwargs): # type: ignore +def stored(key: int) -> Callable[[ByteFunc[P]], ByteFunc[P]]: + def decorator(func: ByteFunc[P]) -> ByteFunc[P]: + def wrapper(*args: P.args, **kwargs: P.kwargs): value = get(key) if value is None: value = func(*args, **kwargs) set(key, value) return value - return wrapper # type: ignore + return wrapper return decorator -def stored_async(key: int) -> Callable[[AsyncByteFunc], AsyncByteFunc]: - def decorator(func: AsyncByteFunc) -> AsyncByteFunc: - # assert isinstance(func, type(lambda: (yield))), "do not use stored_async" - # XXX the test above fails for closures - # We shouldn't need this test here anyway: the 'await func()' should fail - # with functions that do not return an awaitable so the problem is more visible. - - async def wrapper(*args, **kwargs): # type: ignore +def stored_async(key: int) -> Callable[[AsyncByteFunc[P]], AsyncByteFunc[P]]: + def decorator(func: AsyncByteFunc[P]) -> AsyncByteFunc[P]: + async def wrapper(*args: P.args, **kwargs: P.kwargs): value = get(key) if value is None: value = await func(*args, **kwargs) set(key, value) return value - return wrapper # type: ignore + return wrapper return decorator diff --git a/core/src/storage/device.py b/core/src/storage/device.py index 627786f4f..c50aa1766 100644 --- a/core/src/storage/device.py +++ b/core/src/storage/device.py @@ -1,10 +1,11 @@ from micropython import const +from typing import TYPE_CHECKING from ubinascii import hexlify import storage.cache from storage import common -if False: +if TYPE_CHECKING: from trezor.enums import BackupType from typing_extensions import Literal @@ -39,7 +40,7 @@ _EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty) SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0) SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1) _DEFAULT_SAFETY_CHECK_LEVEL = SAFETY_CHECK_LEVEL_STRICT -if False: +if TYPE_CHECKING: StorageSafetyCheckLevel = Literal[0, 1] # fmt: on diff --git a/core/src/storage/sd_salt.py b/core/src/storage/sd_salt.py index 653b53d4c..e0a204a34 100644 --- a/core/src/storage/sd_salt.py +++ b/core/src/storage/sd_salt.py @@ -1,11 +1,12 @@ from micropython import const +from typing import TYPE_CHECKING import storage.device from trezor import io from trezor.sdcard import with_filesystem from trezor.utils import consteq -if False: +if TYPE_CHECKING: from typing import TypeVar, Callable T = TypeVar("T", bound=Callable) diff --git a/core/src/trezor/_proto_messages.mako b/core/src/trezor/_proto_messages.mako index ae9b149f7..097363276 100644 --- a/core/src/trezor/_proto_messages.mako +++ b/core/src/trezor/_proto_messages.mako @@ -4,10 +4,7 @@ from trezor import protobuf -if False: - from typing import TYPE_CHECKING, Any, TypeGuard -else: - TYPE_CHECKING = False +from typing import Any, TYPE_CHECKING def __getattr__(name: str) -> Any: @@ -18,6 +15,7 @@ def __getattr__(name: str) -> Any: if TYPE_CHECKING: + from typing import TypeGuard % for enum in sorted(enums, key=lambda e: e.name): from trezor.enums import ${enum.name} # noqa: F401 % endfor diff --git a/core/src/trezor/crypto/base58.py b/core/src/trezor/crypto/base58.py index 310439807..80e99bc92 100644 --- a/core/src/trezor/crypto/base58.py +++ b/core/src/trezor/crypto/base58.py @@ -13,8 +13,7 @@ # This module adds shiny packaging and support for python3. # -if False: - from typing import Callable +from typing import Callable # 58 character alphabet used _alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" diff --git a/core/src/trezor/crypto/bech32.py b/core/src/trezor/crypto/bech32.py index 7edbd6af9..1d206258a 100644 --- a/core/src/trezor/crypto/bech32.py +++ b/core/src/trezor/crypto/bech32.py @@ -20,7 +20,9 @@ """Reference implementation for Bech32/Bech32m and segwit addresses.""" -if False: +from typing import TYPE_CHECKING + +if TYPE_CHECKING: from enum import IntEnum from typing import Iterable, Union, TypeVar @@ -138,7 +140,7 @@ def decode(hrp: str, addr: str) -> OptionalTuple2[int, list[int]]: """Decode a segwit address.""" hrpgot, data, spec = bech32_decode(addr) # the following two lines are strictly not required - # but they make mypy happy + # but they make typecheckers happy if data is None: return (None, None) if hrpgot != hrp: diff --git a/core/src/trezor/crypto/der.py b/core/src/trezor/crypto/der.py index f8525507d..2b346a5aa 100644 --- a/core/src/trezor/crypto/der.py +++ b/core/src/trezor/crypto/der.py @@ -1,8 +1,9 @@ from micropython import const +from typing import TYPE_CHECKING from trezor.utils import BufferReader, empty_bytearray -if False: +if TYPE_CHECKING: from trezor.utils import Writer # Maximum length of a DER-encoded secp256k1 or secp256p1 signature. @@ -79,7 +80,7 @@ def read_int(r: BufferReader) -> memoryview: return r.read_memoryview(n) -def encode_seq(seq: tuple) -> bytes: +def encode_seq(seq: tuple[bytes, ...]) -> bytes: # Preallocate space for a signature, which is all that this function ever encodes. buffer = empty_bytearray(MAX_DER_SIGNATURE_LENGTH) buffer.append(0x30) diff --git a/core/src/trezor/crypto/rlp.py b/core/src/trezor/crypto/rlp.py index d593c25c4..0e892c16d 100644 --- a/core/src/trezor/crypto/rlp.py +++ b/core/src/trezor/crypto/rlp.py @@ -1,6 +1,7 @@ from micropython import const +from typing import TYPE_CHECKING -if False: +if TYPE_CHECKING: from typing import Union from trezor.utils import Writer diff --git a/core/src/trezor/crypto/slip39.py b/core/src/trezor/crypto/slip39.py index 5032f3af2..257ca7169 100644 --- a/core/src/trezor/crypto/slip39.py +++ b/core/src/trezor/crypto/slip39.py @@ -32,11 +32,12 @@ See https://github.com/satoshilabs/slips/blob/master/slip-0039.md. from micropython import const from trezorcrypto import shamir, slip39 +from typing import TYPE_CHECKING from trezor.crypto import hmac, pbkdf2, random from trezor.errors import MnemonicError -if False: +if TYPE_CHECKING: from typing import Callable, Iterable, Tuple Indices = Tuple[int, ...] diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index aaf9e6efa..c73bc3b3d 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -1,8 +1,4 @@ -if False: - from typing import TYPE_CHECKING -else: - TYPE_CHECKING = False - +from typing import TYPE_CHECKING if TYPE_CHECKING: from enum import IntEnum diff --git a/core/src/trezor/enums/_proto_init.mako b/core/src/trezor/enums/_proto_init.mako index c23cb3ad0..9622aaca2 100644 --- a/core/src/trezor/enums/_proto_init.mako +++ b/core/src/trezor/enums/_proto_init.mako @@ -1,8 +1,4 @@ -if False: - from typing import TYPE_CHECKING -else: - TYPE_CHECKING = False - +from typing import TYPE_CHECKING if TYPE_CHECKING: from enum import IntEnum diff --git a/core/src/trezor/log.py b/core/src/trezor/log.py index 0ead6cb49..39f906c2a 100644 --- a/core/src/trezor/log.py +++ b/core/src/trezor/log.py @@ -1,9 +1,7 @@ import sys import utime from micropython import const - -if False: - from typing import Any +from typing import Any NOTSET = const(0) DEBUG = const(10) @@ -60,7 +58,7 @@ def critical(name: str, msg: str, *args: Any) -> None: def exception(name: str, exc: BaseException) -> None: # we are using `__class__.__name__` to avoid importing ui module - # we also need to instruct mypy to ignore the missing argument + # we also need to instruct typechecker to ignore the missing argument # in ui.Result exception if exc.__class__.__name__ == "Result": _log( diff --git a/core/src/trezor/loop.py b/core/src/trezor/loop.py index 46e9fd8be..d099d6357 100644 --- a/core/src/trezor/loop.py +++ b/core/src/trezor/loop.py @@ -9,10 +9,11 @@ See `schedule`, `run`, and syscalls `sleep`, `wait`, `signal` and `race`. import utime import utimeq +from typing import TYPE_CHECKING from trezor import io, log -if False: +if TYPE_CHECKING: from typing import ( Any, Awaitable, @@ -21,7 +22,8 @@ if False: Generator, ) - Task = Coroutine + Task = Coroutine | Generator + AwaitableTask = Task | Awaitable Finalizer = Callable[[Task, Any], None] # function to call after every task step @@ -208,12 +210,14 @@ class Syscall: scheduler, they do so through instances of a class derived from `Syscall`. """ - def __iter__(self) -> Task: # type: ignore + def __iter__(self) -> Generator: # support `yield from` or `await` on syscalls return (yield self) - def __await__(self) -> Generator: - return self.__iter__() # type: ignore + if TYPE_CHECKING: + + def __await__(self) -> Generator: + return self.__iter__() def handle(self, task: Task) -> None: pass @@ -261,7 +265,7 @@ class wait(Syscall): pause(task, self.msg_iface) -_type_gen = type((lambda: (yield))()) +_type_gen: type[Generator] = type((lambda: (yield))()) class race(Syscall): @@ -290,10 +294,10 @@ class race(Syscall): `race.__iter__` for explanation. Always use `await`. """ - def __init__(self, *children: Awaitable, exit_others: bool = True) -> None: + def __init__(self, *children: AwaitableTask, exit_others: bool = True) -> None: self.children = children self.exit_others = exit_others - self.finished: list[Awaitable] = [] # children that finished + self.finished: list[AwaitableTask] = [] # children that finished self.scheduled: list[Task] = [] # scheduled wrapper tasks def handle(self, task: Task) -> None: @@ -309,13 +313,19 @@ class race(Syscall): finished.clear() for child in self.children: + child_task: Task if isinstance(child, _type_gen): + # child is a coroutine/generator + # i.e., async function, or function using yield (these are identical + # in micropython) child_task = child else: - child_task = iter(child) # type: ignore + # child is a layout -- type-wise, it is an Awaitable, but + # implementation-wise it is an Iterable and we know that its __iter__ + # will return a Generator. + child_task = child.__iter__() # type: ignore schedule(child_task, None, None, finalizer) scheduled.append(child_task) - # TODO: document the types here def exit(self, except_for: Task | None = None) -> None: for task in self.scheduled: @@ -330,6 +340,8 @@ class race(Syscall): if child_task is task: child = self.children[index] break + else: + raise RuntimeError # task not found in scheduled self.finished.append(child) if self.exit_others: self.exit(task) @@ -485,6 +497,8 @@ class spawn(Syscall): # schedule task immediately if __debug__: log.debug(__name__, "spawn new task: %s", task) + + assert isinstance(task, _type_gen) schedule(task, finalizer=self._finalize) def _finalize(self, task: Task, value: Any) -> None: diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index 56634080c..f59e4b841 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -4,10 +4,7 @@ from trezor import protobuf -if False: - from typing import TYPE_CHECKING, Any, TypeGuard -else: - TYPE_CHECKING = False +from typing import Any, TYPE_CHECKING def __getattr__(name: str) -> Any: @@ -18,6 +15,7 @@ def __getattr__(name: str) -> Any: if TYPE_CHECKING: + from typing import TypeGuard from trezor.enums import AmountUnit # noqa: F401 from trezor.enums import BackupType # noqa: F401 from trezor.enums import BinanceOrderSide # noqa: F401 @@ -119,23 +117,23 @@ if TYPE_CHECKING: class BinanceSignTx(protobuf.MessageType): address_n: "list[int]" - msg_count: "int | None" - account_number: "int | None" + msg_count: "int" + account_number: "int" chain_id: "str | None" memo: "str | None" - sequence: "int | None" - source: "int | None" + sequence: "int" + source: "int" def __init__( self, *, + msg_count: "int", + account_number: "int", + sequence: "int", + source: "int", address_n: "list[int] | None" = None, - msg_count: "int | None" = None, - account_number: "int | None" = None, chain_id: "str | None" = None, memo: "str | None" = None, - sequence: "int | None" = None, - source: "int | None" = None, ) -> None: pass @@ -167,25 +165,25 @@ if TYPE_CHECKING: class BinanceOrderMsg(protobuf.MessageType): id: "str | None" - ordertype: "BinanceOrderType | None" - price: "int | None" - quantity: "int | None" + ordertype: "BinanceOrderType" + price: "int" + quantity: "int" sender: "str | None" - side: "BinanceOrderSide | None" + side: "BinanceOrderSide" symbol: "str | None" - timeinforce: "BinanceTimeInForce | None" + timeinforce: "BinanceTimeInForce" def __init__( self, *, + ordertype: "BinanceOrderType", + price: "int", + quantity: "int", + side: "BinanceOrderSide", + timeinforce: "BinanceTimeInForce", id: "str | None" = None, - ordertype: "BinanceOrderType | None" = None, - price: "int | None" = None, - quantity: "int | None" = None, sender: "str | None" = None, - side: "BinanceOrderSide | None" = None, symbol: "str | None" = None, - timeinforce: "BinanceTimeInForce | None" = None, ) -> None: pass @@ -228,14 +226,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class BinanceInputOutput(protobuf.MessageType): - address: "str | None" + address: "str" coins: "list[BinanceCoin]" def __init__( self, *, + address: "str", coins: "list[BinanceCoin] | None" = None, - address: "str | None" = None, ) -> None: pass @@ -244,14 +242,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class BinanceCoin(protobuf.MessageType): - amount: "int | None" - denom: "str | None" + amount: "int" + denom: "str" def __init__( self, *, - amount: "int | None" = None, - denom: "str | None" = None, + amount: "int", + denom: "str", ) -> None: pass @@ -2531,17 +2529,17 @@ if TYPE_CHECKING: class EosSignTx(protobuf.MessageType): address_n: "list[int]" - chain_id: "bytes | None" - header: "EosTxHeader | None" - num_actions: "int | None" + chain_id: "bytes" + header: "EosTxHeader" + num_actions: "int" def __init__( self, *, + chain_id: "bytes", + header: "EosTxHeader", + num_actions: "int", address_n: "list[int] | None" = None, - chain_id: "bytes | None" = None, - header: "EosTxHeader | None" = None, - num_actions: "int | None" = None, ) -> None: pass @@ -2564,7 +2562,7 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosTxActionAck(protobuf.MessageType): - common: "EosActionCommon | None" + common: "EosActionCommon" transfer: "EosActionTransfer | None" delegate: "EosActionDelegate | None" undelegate: "EosActionUndelegate | None" @@ -2583,7 +2581,7 @@ if TYPE_CHECKING: def __init__( self, *, - common: "EosActionCommon | None" = None, + common: "EosActionCommon", transfer: "EosActionTransfer | None" = None, delegate: "EosActionDelegate | None" = None, undelegate: "EosActionUndelegate | None" = None, @@ -2644,14 +2642,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosAsset(protobuf.MessageType): - amount: "int | None" - symbol: "int | None" + amount: "int" + symbol: "int" def __init__( self, *, - amount: "int | None" = None, - symbol: "int | None" = None, + amount: "int", + symbol: "int", ) -> None: pass @@ -2660,14 +2658,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosPermissionLevel(protobuf.MessageType): - actor: "int | None" - permission: "int | None" + actor: "int" + permission: "int" def __init__( self, *, - actor: "int | None" = None, - permission: "int | None" = None, + actor: "int", + permission: "int", ) -> None: pass @@ -2696,14 +2694,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosAuthorizationAccount(protobuf.MessageType): - account: "EosPermissionLevel | None" - weight: "int | None" + account: "EosPermissionLevel" + weight: "int" def __init__( self, *, - account: "EosPermissionLevel | None" = None, - weight: "int | None" = None, + account: "EosPermissionLevel", + weight: "int", ) -> None: pass @@ -2712,14 +2710,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosAuthorizationWait(protobuf.MessageType): - wait_sec: "int | None" - weight: "int | None" + wait_sec: "int" + weight: "int" def __init__( self, *, - wait_sec: "int | None" = None, - weight: "int | None" = None, + wait_sec: "int", + weight: "int", ) -> None: pass @@ -2728,7 +2726,7 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosAuthorization(protobuf.MessageType): - threshold: "int | None" + threshold: "int" keys: "list[EosAuthorizationKey]" accounts: "list[EosAuthorizationAccount]" waits: "list[EosAuthorizationWait]" @@ -2736,10 +2734,10 @@ if TYPE_CHECKING: def __init__( self, *, + threshold: "int", keys: "list[EosAuthorizationKey] | None" = None, accounts: "list[EosAuthorizationAccount] | None" = None, waits: "list[EosAuthorizationWait] | None" = None, - threshold: "int | None" = None, ) -> None: pass @@ -2748,16 +2746,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionCommon(protobuf.MessageType): - account: "int | None" - name: "int | None" + account: "int" + name: "int" authorization: "list[EosPermissionLevel]" def __init__( self, *, + account: "int", + name: "int", authorization: "list[EosPermissionLevel] | None" = None, - account: "int | None" = None, - name: "int | None" = None, ) -> None: pass @@ -2766,18 +2764,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionTransfer(protobuf.MessageType): - sender: "int | None" - receiver: "int | None" - quantity: "EosAsset | None" - memo: "str | None" + sender: "int" + receiver: "int" + quantity: "EosAsset" + memo: "str" def __init__( self, *, - sender: "int | None" = None, - receiver: "int | None" = None, - quantity: "EosAsset | None" = None, - memo: "str | None" = None, + sender: "int", + receiver: "int", + quantity: "EosAsset", + memo: "str", ) -> None: pass @@ -2786,20 +2784,20 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionDelegate(protobuf.MessageType): - sender: "int | None" - receiver: "int | None" - net_quantity: "EosAsset | None" - cpu_quantity: "EosAsset | None" - transfer: "bool | None" + sender: "int" + receiver: "int" + net_quantity: "EosAsset" + cpu_quantity: "EosAsset" + transfer: "bool" def __init__( self, *, - sender: "int | None" = None, - receiver: "int | None" = None, - net_quantity: "EosAsset | None" = None, - cpu_quantity: "EosAsset | None" = None, - transfer: "bool | None" = None, + sender: "int", + receiver: "int", + net_quantity: "EosAsset", + cpu_quantity: "EosAsset", + transfer: "bool", ) -> None: pass @@ -2808,18 +2806,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionUndelegate(protobuf.MessageType): - sender: "int | None" - receiver: "int | None" - net_quantity: "EosAsset | None" - cpu_quantity: "EosAsset | None" + sender: "int" + receiver: "int" + net_quantity: "EosAsset" + cpu_quantity: "EosAsset" def __init__( self, *, - sender: "int | None" = None, - receiver: "int | None" = None, - net_quantity: "EosAsset | None" = None, - cpu_quantity: "EosAsset | None" = None, + sender: "int", + receiver: "int", + net_quantity: "EosAsset", + cpu_quantity: "EosAsset", ) -> None: pass @@ -2828,12 +2826,12 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionRefund(protobuf.MessageType): - owner: "int | None" + owner: "int" def __init__( self, *, - owner: "int | None" = None, + owner: "int", ) -> None: pass @@ -2842,16 +2840,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionBuyRam(protobuf.MessageType): - payer: "int | None" - receiver: "int | None" - quantity: "EosAsset | None" + payer: "int" + receiver: "int" + quantity: "EosAsset" def __init__( self, *, - payer: "int | None" = None, - receiver: "int | None" = None, - quantity: "EosAsset | None" = None, + payer: "int", + receiver: "int", + quantity: "EosAsset", ) -> None: pass @@ -2860,16 +2858,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionBuyRamBytes(protobuf.MessageType): - payer: "int | None" - receiver: "int | None" - bytes: "int | None" + payer: "int" + receiver: "int" + bytes: "int" def __init__( self, *, - payer: "int | None" = None, - receiver: "int | None" = None, - bytes: "int | None" = None, + payer: "int", + receiver: "int", + bytes: "int", ) -> None: pass @@ -2878,14 +2876,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionSellRam(protobuf.MessageType): - account: "int | None" - bytes: "int | None" + account: "int" + bytes: "int" def __init__( self, *, - account: "int | None" = None, - bytes: "int | None" = None, + account: "int", + bytes: "int", ) -> None: pass @@ -2894,16 +2892,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionVoteProducer(protobuf.MessageType): - voter: "int | None" - proxy: "int | None" + voter: "int" + proxy: "int" producers: "list[int]" def __init__( self, *, + voter: "int", + proxy: "int", producers: "list[int] | None" = None, - voter: "int | None" = None, - proxy: "int | None" = None, ) -> None: pass @@ -2912,18 +2910,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionUpdateAuth(protobuf.MessageType): - account: "int | None" - permission: "int | None" - parent: "int | None" - auth: "EosAuthorization | None" + account: "int" + permission: "int" + parent: "int" + auth: "EosAuthorization" def __init__( self, *, - account: "int | None" = None, - permission: "int | None" = None, - parent: "int | None" = None, - auth: "EosAuthorization | None" = None, + account: "int", + permission: "int", + parent: "int", + auth: "EosAuthorization", ) -> None: pass @@ -2932,14 +2930,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionDeleteAuth(protobuf.MessageType): - account: "int | None" - permission: "int | None" + account: "int" + permission: "int" def __init__( self, *, - account: "int | None" = None, - permission: "int | None" = None, + account: "int", + permission: "int", ) -> None: pass @@ -2948,18 +2946,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionLinkAuth(protobuf.MessageType): - account: "int | None" - code: "int | None" - type: "int | None" - requirement: "int | None" + account: "int" + code: "int" + type: "int" + requirement: "int" def __init__( self, *, - account: "int | None" = None, - code: "int | None" = None, - type: "int | None" = None, - requirement: "int | None" = None, + account: "int", + code: "int", + type: "int", + requirement: "int", ) -> None: pass @@ -2968,16 +2966,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionUnlinkAuth(protobuf.MessageType): - account: "int | None" - code: "int | None" - type: "int | None" + account: "int" + code: "int" + type: "int" def __init__( self, *, - account: "int | None" = None, - code: "int | None" = None, - type: "int | None" = None, + account: "int", + code: "int", + type: "int", ) -> None: pass @@ -2986,18 +2984,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class EosActionNewAccount(protobuf.MessageType): - creator: "int | None" - name: "int | None" - owner: "EosAuthorization | None" - active: "EosAuthorization | None" + creator: "int" + name: "int" + owner: "EosAuthorization" + active: "EosAuthorization" def __init__( self, *, - creator: "int | None" = None, - name: "int | None" = None, - owner: "EosAuthorization | None" = None, - active: "EosAuthorization | None" = None, + creator: "int", + name: "int", + owner: "EosAuthorization", + active: "EosAuthorization", ) -> None: pass @@ -3007,13 +3005,13 @@ if TYPE_CHECKING: class EosActionUnknown(protobuf.MessageType): data_size: "int" - data_chunk: "bytes | None" + data_chunk: "bytes" def __init__( self, *, data_size: "int", - data_chunk: "bytes | None" = None, + data_chunk: "bytes", ) -> None: pass @@ -4263,7 +4261,7 @@ if TYPE_CHECKING: class NEMGetAddress(protobuf.MessageType): address_n: "list[int]" - network: "int | None" + network: "int" show_display: "bool | None" def __init__( @@ -4294,7 +4292,7 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMSignTx(protobuf.MessageType): - transaction: "NEMTransactionCommon | None" + transaction: "NEMTransactionCommon" multisig: "NEMTransactionCommon | None" transfer: "NEMTransfer | None" cosigning: "bool | None" @@ -4307,7 +4305,7 @@ if TYPE_CHECKING: def __init__( self, *, - transaction: "NEMTransactionCommon | None" = None, + transaction: "NEMTransactionCommon", multisig: "NEMTransactionCommon | None" = None, transfer: "NEMTransfer | None" = None, cosigning: "bool | None" = None, @@ -4375,20 +4373,20 @@ if TYPE_CHECKING: class NEMTransactionCommon(protobuf.MessageType): address_n: "list[int]" - network: "int | None" - timestamp: "int | None" - fee: "int | None" - deadline: "int | None" + network: "int" + timestamp: "int" + fee: "int" + deadline: "int" signer: "bytes | None" def __init__( self, *, + timestamp: "int", + fee: "int", + deadline: "int", address_n: "list[int] | None" = None, network: "int | None" = None, - timestamp: "int | None" = None, - fee: "int | None" = None, - deadline: "int | None" = None, signer: "bytes | None" = None, ) -> None: pass @@ -4398,18 +4396,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMTransfer(protobuf.MessageType): - recipient: "str | None" - amount: "int | None" - payload: "bytes | None" + recipient: "str" + amount: "int" + payload: "bytes" public_key: "bytes | None" mosaics: "list[NEMMosaic]" def __init__( self, *, + recipient: "str", + amount: "int", mosaics: "list[NEMMosaic] | None" = None, - recipient: "str | None" = None, - amount: "int | None" = None, payload: "bytes | None" = None, public_key: "bytes | None" = None, ) -> None: @@ -4420,18 +4418,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMProvisionNamespace(protobuf.MessageType): - namespace: "str | None" + namespace: "str" parent: "str | None" - sink: "str | None" - fee: "int | None" + sink: "str" + fee: "int" def __init__( self, *, - namespace: "str | None" = None, + namespace: "str", + sink: "str", + fee: "int", parent: "str | None" = None, - sink: "str | None" = None, - fee: "int | None" = None, ) -> None: pass @@ -4440,16 +4438,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMMosaicCreation(protobuf.MessageType): - definition: "NEMMosaicDefinition | None" - sink: "str | None" - fee: "int | None" + definition: "NEMMosaicDefinition" + sink: "str" + fee: "int" def __init__( self, *, - definition: "NEMMosaicDefinition | None" = None, - sink: "str | None" = None, - fee: "int | None" = None, + definition: "NEMMosaicDefinition", + sink: "str", + fee: "int", ) -> None: pass @@ -4458,18 +4456,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMMosaicSupplyChange(protobuf.MessageType): - namespace: "str | None" - mosaic: "str | None" - type: "NEMSupplyChangeType | None" - delta: "int | None" + namespace: "str" + mosaic: "str" + type: "NEMSupplyChangeType" + delta: "int" def __init__( self, *, - namespace: "str | None" = None, - mosaic: "str | None" = None, - type: "NEMSupplyChangeType | None" = None, - delta: "int | None" = None, + namespace: "str", + mosaic: "str", + type: "NEMSupplyChangeType", + delta: "int", ) -> None: pass @@ -4494,14 +4492,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMImportanceTransfer(protobuf.MessageType): - mode: "NEMImportanceTransferMode | None" - public_key: "bytes | None" + mode: "NEMImportanceTransferMode" + public_key: "bytes" def __init__( self, *, - mode: "NEMImportanceTransferMode | None" = None, - public_key: "bytes | None" = None, + mode: "NEMImportanceTransferMode", + public_key: "bytes", ) -> None: pass @@ -4510,16 +4508,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMMosaic(protobuf.MessageType): - namespace: "str | None" - mosaic: "str | None" - quantity: "int | None" + namespace: "str" + mosaic: "str" + quantity: "int" def __init__( self, *, - namespace: "str | None" = None, - mosaic: "str | None" = None, - quantity: "int | None" = None, + namespace: "str", + mosaic: "str", + quantity: "int", ) -> None: pass @@ -4530,8 +4528,8 @@ if TYPE_CHECKING: class NEMMosaicDefinition(protobuf.MessageType): name: "str | None" ticker: "str | None" - namespace: "str | None" - mosaic: "str | None" + namespace: "str" + mosaic: "str" divisibility: "int | None" levy: "NEMMosaicLevy | None" fee: "int | None" @@ -4541,17 +4539,18 @@ if TYPE_CHECKING: supply: "int | None" mutable_supply: "bool | None" transferable: "bool | None" - description: "str | None" + description: "str" networks: "list[int]" def __init__( self, *, + namespace: "str", + mosaic: "str", + description: "str", networks: "list[int] | None" = None, name: "str | None" = None, ticker: "str | None" = None, - namespace: "str | None" = None, - mosaic: "str | None" = None, divisibility: "int | None" = None, levy: "NEMMosaicLevy | None" = None, fee: "int | None" = None, @@ -4561,7 +4560,6 @@ if TYPE_CHECKING: supply: "int | None" = None, mutable_supply: "bool | None" = None, transferable: "bool | None" = None, - description: "str | None" = None, ) -> None: pass @@ -4570,14 +4568,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class NEMCosignatoryModification(protobuf.MessageType): - type: "NEMModificationType | None" - public_key: "bytes | None" + type: "NEMModificationType" + public_key: "bytes" def __init__( self, *, - type: "NEMModificationType | None" = None, - public_key: "bytes | None" = None, + type: "NEMModificationType", + public_key: "bytes", ) -> None: pass @@ -4617,21 +4615,21 @@ if TYPE_CHECKING: class RippleSignTx(protobuf.MessageType): address_n: "list[int]" - fee: "int | None" - flags: "int | None" - sequence: "int | None" + fee: "int" + flags: "int" + sequence: "int" last_ledger_sequence: "int | None" - payment: "RipplePayment | None" + payment: "RipplePayment" def __init__( self, *, + fee: "int", + sequence: "int", + payment: "RipplePayment", address_n: "list[int] | None" = None, - fee: "int | None" = None, flags: "int | None" = None, - sequence: "int | None" = None, last_ledger_sequence: "int | None" = None, - payment: "RipplePayment | None" = None, ) -> None: pass @@ -5306,16 +5304,16 @@ if TYPE_CHECKING: return isinstance(msg, cls) class TezosProposalOp(protobuf.MessageType): - source: "bytes | None" - period: "int | None" + source: "bytes" + period: "int" proposals: "list[bytes]" def __init__( self, *, + source: "bytes", + period: "int", proposals: "list[bytes] | None" = None, - source: "bytes | None" = None, - period: "int | None" = None, ) -> None: pass @@ -5324,18 +5322,18 @@ if TYPE_CHECKING: return isinstance(msg, cls) class TezosBallotOp(protobuf.MessageType): - source: "bytes | None" - period: "int | None" - proposal: "bytes | None" - ballot: "TezosBallotType | None" + source: "bytes" + period: "int" + proposal: "bytes" + ballot: "TezosBallotType" def __init__( self, *, - source: "bytes | None" = None, - period: "int | None" = None, - proposal: "bytes | None" = None, - ballot: "TezosBallotType | None" = None, + source: "bytes", + period: "int", + proposal: "bytes", + ballot: "TezosBallotType", ) -> None: pass @@ -5362,14 +5360,14 @@ if TYPE_CHECKING: return isinstance(msg, cls) class TezosManagerTransfer(protobuf.MessageType): - destination: "TezosContractID | None" - amount: "int | None" + destination: "TezosContractID" + amount: "int" def __init__( self, *, - destination: "TezosContractID | None" = None, - amount: "int | None" = None, + destination: "TezosContractID", + amount: "int", ) -> None: pass diff --git a/core/src/trezor/pin.py b/core/src/trezor/pin.py index c904fa3ed..545df18aa 100644 --- a/core/src/trezor/pin.py +++ b/core/src/trezor/pin.py @@ -1,8 +1,6 @@ -from trezor import utils - -if False: - from typing import Any +from typing import Any +from trezor import utils _previous_progress: int | None = None _previous_seconds: int | None = None diff --git a/core/src/trezor/protobuf.py b/core/src/trezor/protobuf.py index 6fc9b82b9..ff862d9d1 100644 --- a/core/src/trezor/protobuf.py +++ b/core/src/trezor/protobuf.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + import trezorproto decode = trezorproto.decode @@ -6,26 +8,25 @@ encoded_length = trezorproto.encoded_length type_for_name = trezorproto.type_for_name type_for_wire = trezorproto.type_for_wire -# XXX -# Note that MessageType "subclasses" are not true subclasses, but instead instances -# of the built-in metaclass MsgDef. MessageType instances are in fact instances of -# the built-in type Msg. That is why isinstance checks do not work, and instead the -# MessageTypeSubclass.is_type_of() method must be used. -if False: - from typing import Type, TypeGuard, TypeVar +if TYPE_CHECKING: + # XXX + # Note that MessageType "subclasses" are not true subclasses, but instead instances + # of the built-in metaclass MsgDef. MessageType instances are in fact instances of + # the built-in type Msg. That is why isinstance checks do not work, and instead the + # MessageTypeSubclass.is_type_of() method must be used. + from typing import TypeGuard, TypeVar T = TypeVar("T", bound="MessageType") - class MsgDef(type): + class MessageType: + MESSAGE_NAME: str = "MessageType" + MESSAGE_WIRE_TYPE: int | None = None + @classmethod - def is_type_of(cls: Type[Type[T]], msg: "MessageType") -> TypeGuard[T]: + def is_type_of(cls: type[T], msg: "MessageType") -> TypeGuard[T]: """Identify if the provided message belongs to this type.""" raise NotImplementedError - class MessageType(metaclass=MsgDef): - MESSAGE_NAME: str = "MessageType" - MESSAGE_WIRE_TYPE: int | None = None - def load_message_buffer( buffer: bytes, diff --git a/core/src/trezor/sdcard.py b/core/src/trezor/sdcard.py index 27cfe963e..f079076ea 100644 --- a/core/src/trezor/sdcard.py +++ b/core/src/trezor/sdcard.py @@ -2,13 +2,27 @@ try: from trezorio import fatfs, sdcard HAVE_SDCARD = True + is_present = sdcard.is_present # type: ignore + capacity = sdcard.capacity # type: ignore + except Exception: HAVE_SDCARD = False -if False: + def is_present() -> bool: + return False + + def capacity() -> int: + return 0 + + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: from typing import Any, Callable, TypeVar + from typing_extensions import ParamSpec - T = TypeVar("T", bound=Callable) + P = ParamSpec("P") + R = TypeVar("R") class FilesystemWrapper: @@ -57,22 +71,9 @@ def filesystem(mounted: bool = True) -> FilesystemWrapper: return FilesystemWrapper.get_instance(mounted=mounted) -def with_filesystem(func: T) -> T: - def wrapped_func(*args, **kwargs) -> Any: # type: ignore +def with_filesystem(func: Callable[P, R]) -> Callable[P, R]: + def wrapped_func(*args: P.args, **kwargs: P.kwargs) -> R: with filesystem(): return func(*args, **kwargs) - return wrapped_func # type: ignore - - -if HAVE_SDCARD: - is_present = sdcard.is_present - capacity = sdcard.capacity - -else: - - def is_present() -> bool: - return False - - def capacity() -> int: - return 0 + return wrapped_func diff --git a/core/src/trezor/ui/__init__.py b/core/src/trezor/ui/__init__.py index 881b86109..9431e0120 100644 --- a/core/src/trezor/ui/__init__.py +++ b/core/src/trezor/ui/__init__.py @@ -3,15 +3,15 @@ import math import utime from micropython import const from trezorui import Display +from typing import TYPE_CHECKING from trezor import io, loop, res, utils, workflow -if False: - from typing import Any, Awaitable, Generator, TypeVar +if TYPE_CHECKING: + from typing import Any, Awaitable, Generator Pos = tuple[int, int] Area = tuple[int, int, int, int] - ResultValue = TypeVar("ResultValue") # all rendering is done through a singleton of `Display` display = Display() @@ -45,7 +45,7 @@ if __debug__: else: - refresh = display.refresh + refresh = display.refresh # type: ignore # in both debug and production, emulator needs to draw the screen explicitly @@ -298,7 +298,7 @@ class Result(Exception): See `Layout.__iter__` for details. """ - def __init__(self, value: ResultValue) -> None: + def __init__(self, value: Any) -> None: super().__init__() self.value = value @@ -327,7 +327,7 @@ class Layout(Component): BACKLIGHT_LEVEL = style.BACKLIGHT_NORMAL RENDER_SLEEP: loop.Syscall = loop.sleep(_RENDER_DELAY_MS) - async def __iter__(self) -> ResultValue: + async def __iter__(self) -> Any: """ Run the layout and wait until it completes. Returns the result value. Usually not overridden. @@ -357,10 +357,15 @@ class Layout(Component): value = result.value return value - def __await__(self) -> Generator[Any, Any, ResultValue]: - return self.__iter__() # type: ignore + if TYPE_CHECKING: - def create_tasks(self) -> tuple[loop.Task, ...]: + def __await__(self) -> Generator: + return self.__iter__() # type: ignore + + else: + __await__ = __iter__ + + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: """ Called from `__iter__`. Creates and returns a sequence of tasks that run this layout. Tasks are executed in parallel. When one of them @@ -371,7 +376,7 @@ class Layout(Component): if utils.MODEL == "T": - def handle_input(self) -> loop.Task: # type: ignore + def handle_input(self) -> Generator: """Task that is waiting for the user input.""" touch = loop.wait(io.TOUCH) while True: @@ -385,7 +390,7 @@ class Layout(Component): elif utils.MODEL == "1": - def handle_input(self) -> loop.Task: # type: ignore + def handle_input(self) -> Generator: """Task that is waiting for the user input.""" button = loop.wait(io.BUTTON) while True: diff --git a/core/src/trezor/ui/components/common/confirm.py b/core/src/trezor/ui/components/common/confirm.py index 80202e141..86676dd3b 100644 --- a/core/src/trezor/ui/components/common/confirm.py +++ b/core/src/trezor/ui/components/common/confirm.py @@ -1,6 +1,8 @@ +from typing import TYPE_CHECKING + from trezor import loop, ui, wire -if False: +if TYPE_CHECKING: from typing import Callable, Any, Awaitable, TypeVar T = TypeVar("T") @@ -68,7 +70,7 @@ class ConfirmBase(ui.Layout): def read_content(self) -> list[str]: return self.content.read_content() - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import confirm_signal return super().create_tasks() + (confirm_signal(),) diff --git a/core/src/trezor/ui/components/common/text.py b/core/src/trezor/ui/components/common/text.py index af162fd89..7329c4ab2 100644 --- a/core/src/trezor/ui/components/common/text.py +++ b/core/src/trezor/ui/components/common/text.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import ui @@ -15,7 +16,7 @@ from ...constants import ( LINE_WIDTH = ui.WIDTH - TEXT_MARGIN_LEFT LINE_WIDTH_PAGINATED = LINE_WIDTH - PAGINATION_MARGIN_RIGHT -if False: +if TYPE_CHECKING: from typing import Any, Sequence, Union TextContent = Union[str, int] diff --git a/core/src/trezor/ui/components/tt/button.py b/core/src/trezor/ui/components/tt/button.py index a8aab4c40..3ae7b195d 100644 --- a/core/src/trezor/ui/components/tt/button.py +++ b/core/src/trezor/ui/components/tt/button.py @@ -1,11 +1,16 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import ui from trezor.ui import display, in_area -if False: +if TYPE_CHECKING: from typing import Union + ButtonContent = Union[str, bytes] + ButtonStyleType = type["ButtonDefault"] + ButtonStyleStateType = type["ButtonDefault.normal"] + class ButtonDefault: class normal: @@ -109,12 +114,6 @@ class ButtonMonoConfirm(ButtonDefault): text_style = ui.MONO -if False: - ButtonContent = Union[str, bytes, None] - ButtonStyleType = type[ButtonDefault] - ButtonStyleStateType = type[ButtonDefault.normal] - - # button states _INITIAL = const(0) _PRESSED = const(1) @@ -166,6 +165,8 @@ class Button(ui.Component): s = self.disabled_style elif self.state is _PRESSED: s = self.active_style + else: + raise RuntimeError # invalid state ax, ay, aw, ah = self.area self.render_background(s, ax, ay, aw, ah) self.render_content(s, ax, ay, aw, ah) diff --git a/core/src/trezor/ui/components/tt/checklist.py b/core/src/trezor/ui/components/tt/checklist.py index c4669a0b4..dc82318fd 100644 --- a/core/src/trezor/ui/components/tt/checklist.py +++ b/core/src/trezor/ui/components/tt/checklist.py @@ -1,10 +1,11 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import res, ui from ...constants import TEXT_HEADER_HEIGHT, TEXT_LINE_HEIGHT -if False: +if TYPE_CHECKING: from typing import Iterable, Union ChecklistItem = Union[str, Iterable[str]] diff --git a/core/src/trezor/ui/components/tt/confirm.py b/core/src/trezor/ui/components/tt/confirm.py index 30f4c4bb9..6e4a4a3cf 100644 --- a/core/src/trezor/ui/components/tt/confirm.py +++ b/core/src/trezor/ui/components/tt/confirm.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import loop, res, ui, utils from trezor.ui.loader import Loader, LoaderDefault @@ -6,7 +7,7 @@ from trezor.ui.loader import Loader, LoaderDefault from ..common.confirm import CANCELLED, CONFIRMED, INFO, ConfirmBase, Pageable from .button import Button, ButtonAbort, ButtonCancel, ButtonConfirm, ButtonDefault -if False: +if TYPE_CHECKING: from typing import Any from .button import ButtonContent, ButtonStyleType from trezor.ui.loader import LoaderStyleType @@ -39,7 +40,7 @@ class Confirm(ConfirmBase): else: area = ui.grid(9, n_x=2) button_confirm = Button(area, confirm, confirm_style) - button_confirm.on_click = self.on_confirm # type: ignore + button_confirm.on_click = self.on_confirm if cancel is not None: if confirm is None: @@ -49,7 +50,7 @@ class Confirm(ConfirmBase): else: area = ui.grid(8, n_x=2) button_cancel = Button(area, cancel, cancel_style) - button_cancel.on_click = self.on_cancel # type: ignore + button_cancel.on_click = self.on_cancel super().__init__(content, button_confirm, button_cancel) @@ -87,7 +88,7 @@ class ConfirmPageable(Confirm): if self.cancel is not None: self.cancel.repaint = True - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: tasks = super().create_tasks() if self.pageable.page_count() > 1: return tasks + (self.handle_paging(),) @@ -171,7 +172,7 @@ class InfoConfirm(ui.Layout): def read_content(self) -> list[str]: return self.content.read_content() - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import confirm_signal return super().create_tasks() + (confirm_signal(),) @@ -250,7 +251,7 @@ class HoldToConfirm(ui.Layout): def read_content(self) -> list[str]: return self.content.read_content() - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import confirm_signal return super().create_tasks() + (confirm_signal(),) diff --git a/core/src/trezor/ui/components/tt/info.py b/core/src/trezor/ui/components/tt/info.py index 0ed3ef119..01465c0a6 100644 --- a/core/src/trezor/ui/components/tt/info.py +++ b/core/src/trezor/ui/components/tt/info.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import res, ui from ...constants import TEXT_LINE_HEIGHT, TEXT_MARGIN_LEFT @@ -5,9 +7,11 @@ from .button import Button, ButtonConfirm from .confirm import CONFIRMED from .text import render_text -if False: +if TYPE_CHECKING: from .button import ButtonContent + InfoConfirmStyleType = type["DefaultInfoConfirm"] + class DefaultInfoConfirm: @@ -22,10 +26,6 @@ class DefaultInfoConfirm: border_color = ui.BLACKISH -if False: - InfoConfirmStyleType = type[DefaultInfoConfirm] - - class InfoConfirm(ui.Layout): DEFAULT_CONFIRM = res.load(ui.ICON_CONFIRM) DEFAULT_STYLE = DefaultInfoConfirm diff --git a/core/src/trezor/ui/components/tt/keyboard_bip39.py b/core/src/trezor/ui/components/tt/keyboard_bip39.py index d63162a6b..625e182ae 100644 --- a/core/src/trezor/ui/components/tt/keyboard_bip39.py +++ b/core/src/trezor/ui/components/tt/keyboard_bip39.py @@ -1,10 +1,12 @@ +from typing import TYPE_CHECKING + from trezor import io, loop, res, ui, workflow from trezor.crypto import bip39 from trezor.ui import display from .button import Button, ButtonClear, ButtonMono, ButtonMonoConfirm -if False: +if TYPE_CHECKING: from .button import ButtonContent, ButtonStyleStateType @@ -212,7 +214,7 @@ class Bip39Keyboard(ui.Layout): if __debug__: - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import input_signal return super().create_tasks() + (input_signal(),) diff --git a/core/src/trezor/ui/components/tt/keyboard_slip39.py b/core/src/trezor/ui/components/tt/keyboard_slip39.py index 35c1881fd..5b101b399 100644 --- a/core/src/trezor/ui/components/tt/keyboard_slip39.py +++ b/core/src/trezor/ui/components/tt/keyboard_slip39.py @@ -1,10 +1,12 @@ +from typing import TYPE_CHECKING + from trezor import io, loop, res, ui, workflow from trezor.crypto import slip39 from trezor.ui import display from .button import Button, ButtonClear, ButtonMono, ButtonMonoConfirm -if False: +if TYPE_CHECKING: from .button import ButtonContent, ButtonStyleStateType @@ -222,7 +224,7 @@ class Slip39Keyboard(ui.Layout): if __debug__: - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import input_signal return super().create_tasks() + (input_signal(),) diff --git a/core/src/trezor/ui/components/tt/passphrase.py b/core/src/trezor/ui/components/tt/passphrase.py index aa961ea02..ed8dc9c5e 100644 --- a/core/src/trezor/ui/components/tt/passphrase.py +++ b/core/src/trezor/ui/components/tt/passphrase.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import io, loop, res, ui, workflow from trezor.ui import display @@ -6,7 +7,7 @@ from trezor.ui import display from .button import Button, ButtonClear, ButtonConfirm from .swipe import SWIPE_HORIZONTAL, SWIPE_LEFT, Swipe -if False: +if TYPE_CHECKING: from typing import Iterable from .button import ButtonContent, ButtonStyleStateType @@ -246,7 +247,7 @@ class PassphraseKeyboard(ui.Layout): def on_confirm(self) -> None: raise ui.Result(self.input.text) - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: tasks: tuple[loop.Task, ...] = ( self.handle_input(), self.handle_rendering(), diff --git a/core/src/trezor/ui/components/tt/pin.py b/core/src/trezor/ui/components/tt/pin.py index 93c558755..6592b5342 100644 --- a/core/src/trezor/ui/components/tt/pin.py +++ b/core/src/trezor/ui/components/tt/pin.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import config, res, ui from trezor.crypto import random @@ -6,7 +7,7 @@ from trezor.ui import display from .button import Button, ButtonCancel, ButtonClear, ButtonConfirm, ButtonMono -if False: +if TYPE_CHECKING: from trezor import loop from typing import Iterable @@ -176,7 +177,7 @@ class PinDialog(ui.Layout): if __debug__: - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import input_signal return super().create_tasks() + (input_signal(),) diff --git a/core/src/trezor/ui/components/tt/reset.py b/core/src/trezor/ui/components/tt/reset.py index ad9e8d418..928873c43 100644 --- a/core/src/trezor/ui/components/tt/reset.py +++ b/core/src/trezor/ui/components/tt/reset.py @@ -1,10 +1,12 @@ +from typing import TYPE_CHECKING + from trezor import ui from .button import Button from .num_input import NumInput from .text import Text -if False: +if TYPE_CHECKING: from trezor import loop from typing import Callable, NoReturn, Sequence @@ -50,6 +52,8 @@ class Slip39NumInput(ui.Component): header = "Set num. of groups" elif self.step is Slip39NumInput.SET_GROUP_THRESHOLD: header = "Set group threshold" + else: + raise RuntimeError # invalid step ui.header(header, ui.ICON_RESET, ui.TITLE_GREY, ui.BG, ui.ORANGE_ICON) # render the counter @@ -148,5 +152,5 @@ class MnemonicWordSelect(ui.Layout): def read_content(self) -> list[str]: return self.text.read_content() + [b.text for b in self.buttons] - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: return super().create_tasks() + (debug.input_signal(),) diff --git a/core/src/trezor/ui/components/tt/scroll.py b/core/src/trezor/ui/components/tt/scroll.py index 797dd249c..71f227ceb 100644 --- a/core/src/trezor/ui/components/tt/scroll.py +++ b/core/src/trezor/ui/components/tt/scroll.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from trezor import loop, res, ui, utils, wire, workflow from trezor.enums import ButtonRequestType @@ -16,8 +17,8 @@ from .text import ( Text, ) -if False: - from typing import Callable, Iterable +if TYPE_CHECKING: + from typing import Any, Callable, Iterable from ..common.text import TextContent @@ -25,10 +26,6 @@ if False: WAS_PAGED = object() -if False: - from typing import Any - - def render_scrollbar(pages: int, page: int) -> None: BBOX = const(220) SIZE = const(8) @@ -137,8 +134,8 @@ class Paginated(ui.Layout): return result - def create_tasks(self) -> tuple[loop.Task, ...]: - tasks: tuple[loop.Task, ...] = ( + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: + tasks: tuple[loop.AwaitableTask, ...] = ( self.handle_input(), self.handle_rendering(), self.handle_paging(), @@ -292,7 +289,7 @@ class PaginatedWithButtons(ui.Layout): def read_content(self) -> list[str]: return self.pages[self.page].read_content() - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import confirm_signal return super().create_tasks() + (confirm_signal(),) diff --git a/core/src/trezor/ui/components/tt/swipe.py b/core/src/trezor/ui/components/tt/swipe.py index ae37390c8..009d9293d 100644 --- a/core/src/trezor/ui/components/tt/swipe.py +++ b/core/src/trezor/ui/components/tt/swipe.py @@ -1,10 +1,8 @@ from micropython import const +from typing import Generator from trezor import io, loop, ui -if False: - from typing import Generator - SWIPE_UP = const(0x01) SWIPE_DOWN = const(0x02) SWIPE_LEFT = const(0x04) diff --git a/core/src/trezor/ui/components/tt/word_select.py b/core/src/trezor/ui/components/tt/word_select.py index 57ecf0438..a12e67dd8 100644 --- a/core/src/trezor/ui/components/tt/word_select.py +++ b/core/src/trezor/ui/components/tt/word_select.py @@ -1,8 +1,10 @@ +from typing import TYPE_CHECKING + from trezor import ui from .button import Button -if False: +if TYPE_CHECKING: from trezor import loop # todo improve? @@ -48,7 +50,7 @@ class WordSelector(ui.Layout): if __debug__: - def create_tasks(self) -> tuple[loop.Task, ...]: + def create_tasks(self) -> tuple[loop.AwaitableTask, ...]: from apps.debug import input_signal return super().create_tasks() + (input_signal(),) diff --git a/core/src/trezor/ui/layouts/common.py b/core/src/trezor/ui/layouts/common.py index bc587343a..5e06f60d7 100644 --- a/core/src/trezor/ui/layouts/common.py +++ b/core/src/trezor/ui/layouts/common.py @@ -1,13 +1,15 @@ +from typing import TYPE_CHECKING + from trezor import log, wire, workflow from trezor.enums import ButtonRequestType from trezor.messages import ButtonAck, ButtonRequest -if False: - from typing import Any, Awaitable, Optional, Tuple, Type, Union +if TYPE_CHECKING: + from typing import Any, Awaitable, Optional, Tuple, Union LayoutType = Awaitable[Any] PropertyType = Tuple[Optional[str], Union[str, bytes, None]] - ExceptionType = Union[BaseException, Type[BaseException]] + ExceptionType = Union[BaseException, type[BaseException]] if __debug__: diff --git a/core/src/trezor/ui/layouts/t1.py b/core/src/trezor/ui/layouts/t1.py index 67c6b1104..d102a6b80 100644 --- a/core/src/trezor/ui/layouts/t1.py +++ b/core/src/trezor/ui/layouts/t1.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import log, ui, wire from trezor.enums import ButtonRequestType @@ -5,7 +7,7 @@ from trezorui2 import layout_new_confirm_action from .common import interact -if False: +if TYPE_CHECKING: from typing import NoReturn, Type, Union ExceptionType = Union[BaseException, Type[BaseException]] diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 71637334e..19252e8a2 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -1,4 +1,5 @@ from micropython import const +from typing import TYPE_CHECKING from ubinascii import hexlify from trezor import ui, wire @@ -37,10 +38,11 @@ from ...constants.tt import ( ) from ..common import button_request, interact -if False: +if TYPE_CHECKING: from typing import Awaitable, Iterable, Iterator, NoReturn, Sequence from ..common import PropertyType, ExceptionType + from ...components.tt.button import ButtonContent __all__ = ( @@ -85,8 +87,8 @@ async def confirm_action( description: str | None = None, description_param: str | None = None, description_param_font: int = ui.BOLD, - verb: str | bytes | None = Confirm.DEFAULT_CONFIRM, - verb_cancel: str | bytes | None = Confirm.DEFAULT_CANCEL, + verb: ButtonContent = Confirm.DEFAULT_CONFIRM, + verb_cancel: ButtonContent | None = Confirm.DEFAULT_CANCEL, hold: bool = False, hold_danger: bool = False, icon: str | None = None, # TODO cleanup @ redesign @@ -126,17 +128,23 @@ async def confirm_action( param_font=description_param_font, ) - cls = HoldToConfirm if hold else Confirm - kwargs = {} + layout: ui.Layout if hold_danger: - kwargs = {"loader_style": LoaderDanger, "confirm_style": ButtonCancel} + assert isinstance(verb, str) + layout = HoldToConfirm( + text, + confirm=verb, + loader_style=LoaderDanger, + confirm_style=ButtonCancel, + cancel=verb_cancel is not None, + ) + elif hold: + assert isinstance(verb, str) + layout = HoldToConfirm(text, confirm=verb, cancel=verb_cancel is not None) + else: + layout = Confirm(text, confirm=verb, cancel=verb_cancel) await raise_if_cancelled( - interact( - ctx, - cls(text, confirm=verb, cancel=verb_cancel, **kwargs), - br_type, - br_code, - ), + interact(ctx, layout, br_type, br_code), exc, ) @@ -761,7 +769,7 @@ async def confirm_properties( ctx: wire.GenericContext, br_type: str, title: str, - props: Sequence[PropertyType], + props: Iterable[PropertyType], icon: str = ui.ICON_SEND, # TODO cleanup @ redesign icon_color: int = ui.GREEN, # TODO cleanup @ redesign hold: bool = False, diff --git a/core/src/trezor/ui/layouts/tt/altcoin.py b/core/src/trezor/ui/layouts/tt/altcoin.py index ebbf4d849..755f24d13 100644 --- a/core/src/trezor/ui/layouts/tt/altcoin.py +++ b/core/src/trezor/ui/layouts/tt/altcoin.py @@ -1,3 +1,5 @@ +from typing import Sequence + from trezor import ui, wire from trezor.enums import ButtonRequestType from trezor.utils import chunks_intersperse @@ -9,9 +11,6 @@ from ...components.tt.text import Text from ...constants.tt import MONO_ADDR_PER_LINE from ..common import interact -if False: - from typing import Sequence - async def confirm_total_ethereum( ctx: wire.GenericContext, total_amount: str, gas_price: str, fee_max: str diff --git a/core/src/trezor/ui/layouts/tt/recovery.py b/core/src/trezor/ui/layouts/tt/recovery.py index 73affd792..1655889fe 100644 --- a/core/src/trezor/ui/layouts/tt/recovery.py +++ b/core/src/trezor/ui/layouts/tt/recovery.py @@ -1,3 +1,5 @@ +from typing import Callable, Iterable + from trezor import strings, ui, wire from trezor.crypto.slip39 import MAX_SHARE_COUNT from trezor.enums import ButtonRequestType @@ -16,9 +18,6 @@ from ...components.tt.text import Text from ...components.tt.word_select import WordSelector from ..common import button_request, interact -if False: - from typing import Callable, Iterable - async def request_word_count(ctx: wire.GenericContext, dry_run: bool) -> int: await button_request(ctx, "word_count", code=ButtonRequestType.MnemonicWordCount) diff --git a/core/src/trezor/ui/layouts/tt/reset.py b/core/src/trezor/ui/layouts/tt/reset.py index 92b342e15..2d58ff10a 100644 --- a/core/src/trezor/ui/layouts/tt/reset.py +++ b/core/src/trezor/ui/layouts/tt/reset.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from trezor import ui, utils, wire from trezor.crypto import random from trezor.enums import BackupType, ButtonRequestType @@ -12,7 +14,7 @@ from ...components.tt.scroll import Paginated from ...components.tt.text import Text from ..common import interact -if False: +if TYPE_CHECKING: from typing import Sequence NumberedWords = Sequence[tuple[int, str]] diff --git a/core/src/trezor/ui/layouts/tt/webauthn.py b/core/src/trezor/ui/layouts/tt/webauthn.py index c31ec164d..083ea6db9 100644 --- a/core/src/trezor/ui/layouts/tt/webauthn.py +++ b/core/src/trezor/ui/layouts/tt/webauthn.py @@ -8,14 +8,11 @@ from ...components.tt.text import Text from ...components.tt.webauthn import ConfirmContent from ..common import interact -if False: - from typing import Optional - async def confirm_webauthn( - ctx: Optional[wire.GenericContext], + ctx: wire.GenericContext | None, info: ConfirmInfo, - pageable: Optional[Pageable] = None, + pageable: Pageable | None = None, ) -> bool: if pageable is not None: confirm: ui.Layout = ConfirmPageable(pageable, ConfirmContent(info)) diff --git a/core/src/trezor/ui/loader.py b/core/src/trezor/ui/loader.py index b170acb5c..71e84107a 100644 --- a/core/src/trezor/ui/loader.py +++ b/core/src/trezor/ui/loader.py @@ -1,5 +1,6 @@ import utime from micropython import const +from typing import TYPE_CHECKING from trezor import res, ui, utils from trezor.ui import display @@ -35,7 +36,7 @@ class LoaderNeutral(LoaderDefault): fg_color = ui.FG -if False: +if TYPE_CHECKING: LoaderStyleType = type[LoaderDefault] @@ -124,7 +125,7 @@ class LoadingAnimation(ui.Layout): def __init__(self, style: LoaderStyleType = LoaderDefault) -> None: super().__init__() self.loader = Loader(style) - self.loader.on_finish = self.on_finish # type: ignore + self.loader.on_finish = self.on_finish self.loader.start() def dispatch(self, event: int, x: int, y: int) -> None: diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index 5fa112410..7b1de77fc 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -12,6 +12,7 @@ from trezorutils import ( # noqa: F401 halt, memcpy, ) +from typing import TYPE_CHECKING DISABLE_ANIMATION = 0 @@ -24,7 +25,7 @@ if __debug__: else: LOG_MEMORY = 0 -if False: +if TYPE_CHECKING: from typing import ( Any, Iterator, @@ -124,7 +125,7 @@ def ensure(cond: bool, msg: str | None = None) -> None: raise AssertionError(msg) -if False: +if TYPE_CHECKING: Chunkable = TypeVar("Chunkable", str, Sequence[Any]) @@ -133,9 +134,7 @@ def chunks(items: Chunkable, size: int) -> Iterator[Chunkable]: yield items[i : i + size] -def chunks_intersperse( - items: Chunkable, size: int, sep: str = "\n" -) -> Iterator[Chunkable]: +def chunks_intersperse(items: str, size: int, sep: str = "\n") -> Iterator[str]: first = True for i in range(0, len(items), size): if not first: @@ -145,25 +144,25 @@ def chunks_intersperse( yield items[i : i + size] -if False: +if TYPE_CHECKING: class HashContext(Protocol): def __init__( # pylint: disable=super-init-not-called - self, data: bytes = None + self, __data: bytes = None ) -> None: ... - def update(self, buf: bytes) -> None: + def update(self, __buf: bytes) -> None: ... def digest(self) -> bytes: ... class Writer(Protocol): - def append(self, b: int) -> None: + def append(self, __b: int) -> None: ... - def extend(self, buf: bytes) -> None: + def extend(self, __buf: bytes) -> None: ... @@ -186,7 +185,7 @@ class HashWriter: return self.ctx.digest() -if False: +if TYPE_CHECKING: BufferType = Union[bytearray, memoryview] diff --git a/core/src/trezor/wire/__init__.py b/core/src/trezor/wire/__init__.py index 3248b1bb3..8d18adb93 100644 --- a/core/src/trezor/wire/__init__.py +++ b/core/src/trezor/wire/__init__.py @@ -35,6 +35,8 @@ reads the message's header. When the message type is known the first handler is """ +from typing import TYPE_CHECKING + from storage.cache import InvalidSessionError from trezor import log, loop, protobuf, utils, workflow from trezor.enums import FailureType @@ -46,7 +48,8 @@ from trezor.wire.errors import ActionCancelled, DataError, Error # other packages. from trezor.wire.errors import * # isort:skip # noqa: F401,F403 -if False: + +if TYPE_CHECKING: from typing import ( Any, Awaitable, @@ -54,6 +57,7 @@ if False: Container, Coroutine, Iterable, + Protocol, TypeVar, ) from trezorio import WireInterface @@ -62,19 +66,6 @@ if False: HandlerTask = Coroutine[Any, Any, protobuf.MessageType] Handler = Callable[["Context", Msg], HandlerTask] - -# If set to False protobuf messages marked with "unstable" option are rejected. -experimental_enabled: bool = False - - -def setup(iface: WireInterface, is_debug_session: bool = False) -> None: - """Initialize the wire stack on passed USB interface.""" - loop.schedule(handle_session(iface, codec_v1.SESSION_ID, is_debug_session)) - - -if False: - from typing import Protocol, TypeVar - LoadedMessageType = TypeVar("LoadedMessageType", bound=protobuf.MessageType) class GenericContext(Protocol): @@ -96,6 +87,15 @@ if False: ... +# If set to False protobuf messages marked with "unstable" option are rejected. +experimental_enabled = False + + +def setup(iface: WireInterface, is_debug_session: bool = False) -> None: + """Initialize the wire stack on passed USB interface.""" + loop.schedule(handle_session(iface, codec_v1.SESSION_ID, is_debug_session)) + + def _wrap_protobuf_load( buffer: bytes, expected_type: type[LoadedMessageType], diff --git a/core/src/trezor/wire/codec_v1.py b/core/src/trezor/wire/codec_v1.py index 32d5612f9..e31cf2fe6 100644 --- a/core/src/trezor/wire/codec_v1.py +++ b/core/src/trezor/wire/codec_v1.py @@ -1,11 +1,11 @@ import ustruct from micropython import const +from typing import TYPE_CHECKING from trezor import io, loop, utils -if False: +if TYPE_CHECKING: from typing import Any - from trezorio import WireInterface _REP_LEN = const(64) @@ -24,7 +24,7 @@ INVALID_TYPE = const(-1) # use it at the same time, thus we check this at runtime in debug builds. if __debug__: - class BufferLock: + class BufferLock: # type: ignore def __init__(self) -> None: self.in_use = False @@ -38,7 +38,7 @@ if __debug__: else: - class BufferLock: # type: ignore + class BufferLock: def __enter__(self) -> None: pass diff --git a/core/src/trezor/wire/errors.py b/core/src/trezor/wire/errors.py index 32cc81437..376820b58 100644 --- a/core/src/trezor/wire/errors.py +++ b/core/src/trezor/wire/errors.py @@ -1,12 +1,8 @@ -from trezor.enums import FailureType as F - -# XXX this rename is also required so that `import errors.*` work in wire/__init__.py -# Otherwise, although the revealed type of FailureType is the same in here and there, -# mypy will complain that one is a module and other is Type[FailureType] +from trezor.enums import FailureType class Error(Exception): - def __init__(self, code: F, message: str) -> None: + def __init__(self, code: FailureType, message: str) -> None: super().__init__() self.code = code self.message = message @@ -14,74 +10,74 @@ class Error(Exception): class UnexpectedMessage(Error): def __init__(self, message: str) -> None: - super().__init__(F.UnexpectedMessage, message) + super().__init__(FailureType.UnexpectedMessage, message) class ButtonExpected(Error): def __init__(self, message: str) -> None: - super().__init__(F.ButtonExpected, message) + super().__init__(FailureType.ButtonExpected, message) class DataError(Error): def __init__(self, message: str) -> None: - super().__init__(F.DataError, message) + super().__init__(FailureType.DataError, message) class ActionCancelled(Error): def __init__(self, message: str = "Cancelled") -> None: - super().__init__(F.ActionCancelled, message) + super().__init__(FailureType.ActionCancelled, message) class PinExpected(Error): def __init__(self, message: str) -> None: - super().__init__(F.PinExpected, message) + super().__init__(FailureType.PinExpected, message) class PinCancelled(Error): def __init__(self, message: str = "PIN entry cancelled") -> None: - super().__init__(F.PinCancelled, message) + super().__init__(FailureType.PinCancelled, message) class PinInvalid(Error): def __init__(self, message: str = "PIN invalid") -> None: - super().__init__(F.PinInvalid, message) + super().__init__(FailureType.PinInvalid, message) class InvalidSignature(Error): def __init__(self, message: str) -> None: - super().__init__(F.InvalidSignature, message) + super().__init__(FailureType.InvalidSignature, message) class ProcessError(Error): def __init__(self, message: str) -> None: - super().__init__(F.ProcessError, message) + super().__init__(FailureType.ProcessError, message) class NotEnoughFunds(Error): def __init__(self, message: str) -> None: - super().__init__(F.NotEnoughFunds, message) + super().__init__(FailureType.NotEnoughFunds, message) class NotInitialized(Error): def __init__(self, message: str) -> None: - super().__init__(F.NotInitialized, message) + super().__init__(FailureType.NotInitialized, message) class PinMismatch(Error): def __init__(self, message: str) -> None: - super().__init__(F.PinMismatch, message) + super().__init__(FailureType.PinMismatch, message) class WipeCodeMismatch(Error): def __init__(self, message: str) -> None: - super().__init__(F.WipeCodeMismatch, message) + super().__init__(FailureType.WipeCodeMismatch, message) class InvalidSession(Error): def __init__(self, message: str = "Invalid session") -> None: - super().__init__(F.InvalidSession, message) + super().__init__(FailureType.InvalidSession, message) class FirmwareError(Error): def __init__(self, message: str) -> None: - super().__init__(F.FirmwareError, message) + super().__init__(FailureType.FirmwareError, message) diff --git a/core/src/trezor/workflow.py b/core/src/trezor/workflow.py index c0906fe7e..3b87a7319 100644 --- a/core/src/trezor/workflow.py +++ b/core/src/trezor/workflow.py @@ -1,9 +1,10 @@ import utime +from typing import TYPE_CHECKING import storage.cache from trezor import log, loop -if False: +if TYPE_CHECKING: from typing import Callable IdleCallback = Callable[[], None] diff --git a/core/src/typing.py b/core/src/typing.py index 0fc0c65fd..5e7d5a4a8 100644 --- a/core/src/typing.py +++ b/core/src/typing.py @@ -1,5 +1,6 @@ TYPE_CHECKING = False + class _GenericTypingObject: def __init__(self, *args, **kwargs): pass @@ -12,7 +13,9 @@ class _GenericTypingObject: # dict-like access: Generic[T], Generic[K, V] return self + _TYPING_OBJECT = _GenericTypingObject() + def __getattr__(key): return _TYPING_OBJECT diff --git a/core/src/usb.py b/core/src/usb.py index 4fd0a4d8f..7439dcba6 100644 --- a/core/src/usb.py +++ b/core/src/usb.py @@ -2,6 +2,16 @@ from micropython import const from trezor import io, utils +bus = io.USB( + vendor_id=0x1209, + product_id=0x53C1, + release_num=0x0200, + manufacturer="SatoshiLabs", + product="TREZOR", + interface="TREZOR Interface", + usb21_landing=False, +) + UDP_PORT = 0 WIRE_PORT_OFFSET = const(0) DEBUGLINK_PORT_OFFSET = const(1) @@ -27,6 +37,7 @@ iface_wire = io.WebUSB( ep_out=0x01 + id_wire, emu_port=UDP_PORT + WIRE_PORT_OFFSET, ) +bus.add(iface_wire) # XXXXXXXXXXXXXXXXXXX # @@ -48,6 +59,7 @@ if __debug__ and ENABLE_IFACE_DEBUG: ep_out=0x01 + id_debug, emu_port=UDP_PORT + DEBUGLINK_PORT_OFFSET, ) + bus.add(iface_debug) if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: # interface used for FIDO/U2F and FIDO2/WebAuthn HID transport @@ -78,6 +90,7 @@ if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: ]), # fmt: on ) + bus.add(iface_webauthn) if __debug__ and ENABLE_IFACE_VCP: # interface used for cdc/vcp console emulation (debug messages) @@ -91,20 +104,4 @@ if __debug__ and ENABLE_IFACE_VCP: ep_cmd=0x81 + id_vcp_data, emu_port=UDP_PORT + VCP_PORT_OFFSET, ) - -bus = io.USB( - vendor_id=0x1209, - product_id=0x53C1, - release_num=0x0200, - manufacturer="SatoshiLabs", - product="TREZOR", - interface="TREZOR Interface", - usb21_landing=False, -) -bus.add(iface_wire) -if __debug__ and ENABLE_IFACE_DEBUG: - bus.add(iface_debug) -if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: - bus.add(iface_webauthn) -if __debug__ and ENABLE_IFACE_VCP: bus.add(iface_vcp) diff --git a/core/tests/mock_storage.py b/core/tests/mock_storage.py index ab6afbb37..29eef8715 100644 --- a/core/tests/mock_storage.py +++ b/core/tests/mock_storage.py @@ -16,7 +16,7 @@ class MockStorage: self.namespace.setdefault(app, {}) self.namespace[app][key] = data - def get(self, app: int, key: int, public: bool = False) -> Optional[bytes]: + def get(self, app: int, key: int, public: bool = False) -> bytes | None: self.namespace.setdefault(app, {}) return self.namespace[app].get(key) diff --git a/core/tests/test_apps.eos.check_action.py b/core/tests/test_apps.eos.check_action.py index 8ddcab1c0..87ca4c681 100644 --- a/core/tests/test_apps.eos.check_action.py +++ b/core/tests/test_apps.eos.check_action.py @@ -3,62 +3,49 @@ from common import * if not utils.BITCOIN_ONLY: from apps.eos.actions import check_action from trezor.messages import EosTxActionAck - from trezor.messages import EosActionBuyRam - from trezor.messages import EosActionBuyRamBytes - from trezor.messages import EosActionDelegate - from trezor.messages import EosActionDeleteAuth - from trezor.messages import EosActionLinkAuth - from trezor.messages import EosActionNewAccount - from trezor.messages import EosActionRefund - from trezor.messages import EosActionSellRam - from trezor.messages import EosActionTransfer - from trezor.messages import EosActionUndelegate - from trezor.messages import EosActionUnlinkAuth - from trezor.messages import EosActionUpdateAuth - from trezor.messages import EosActionVoteProducer @unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin") class TestEosActions(unittest.TestCase): def test_check_action(self): # return True - self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'buyram', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(buy_ram_bytes=EosActionBuyRamBytes()), 'buyrambytes', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(sell_ram=EosActionSellRam()), 'sellram', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(delegate=EosActionDelegate()), 'delegatebw', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(undelegate=EosActionDeleteAuth()), 'undelegatebw', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(refund=EosActionRefund()), 'refund', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(vote_producer=EosActionVoteProducer()), 'voteproducer', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(update_auth=EosActionUpdateAuth()), 'updateauth', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(delete_auth=EosActionDeleteAuth()), 'deleteauth', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(link_auth=EosActionLinkAuth()), 'linkauth', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(unlink_auth=EosActionUnlinkAuth()), 'unlinkauth', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(new_account=EosActionNewAccount()), 'newaccount', 'eosio'), True) - self.assertEqual(check_action(EosTxActionAck(transfer=EosActionTransfer()), 'transfer', 'not_eosio'), True) - self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'unknown', 'not_eosio'), True) - self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'buyram', 'buygoods'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), buy_ram=object()), 'buyram', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), buy_ram_bytes=object()), 'buyrambytes', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), sell_ram=object()), 'sellram', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), delegate=object()), 'delegatebw', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), undelegate=object()), 'undelegatebw', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), refund=object()), 'refund', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), vote_producer=object()), 'voteproducer', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), update_auth=object()), 'updateauth', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), delete_auth=object()), 'deleteauth', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), link_auth=object()), 'linkauth', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), unlink_auth=object()), 'unlinkauth', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), new_account=object()), 'newaccount', 'eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), transfer=object()), 'transfer', 'not_eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), unknown=[]), 'unknown', 'not_eosio'), True) + self.assertEqual(check_action(EosTxActionAck(common=object(), unknown=[]), 'buyram', 'buygoods'), True) # returns False - self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'buyram', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(), 'buyram', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(buy_ram_bytes=EosActionBuyRamBytes()), 'buyrambytes', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(sell_ram=EosActionSellRam()), 'sellram', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(delegate=EosActionDelegate()), 'delegatebw', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(undelegate=EosActionDeleteAuth()), 'undelegatebw', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(refund=EosActionRefund()), 'refund', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(), 'refund', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(vote_producer=EosActionVoteProducer()), 'voteproducer', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(update_auth=EosActionUpdateAuth()), 'updateauth', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(delete_auth=EosActionDeleteAuth()), 'deleteauth', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(link_auth=EosActionLinkAuth()), 'linkauth', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(unlink_auth=EosActionUnlinkAuth()), 'unlinkauth', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(), 'unlinkauth', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(new_account=EosActionNewAccount()), 'newaccount', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(transfer=EosActionTransfer()), 'transfer', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(), 'unknown', 'not_eosio'), False) - self.assertEqual(check_action(EosTxActionAck(buy_ram=EosActionBuyRam()), 'test', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'buyram', 'eosio'), False) - self.assertEqual(check_action(EosTxActionAck(unknown=[]), 'transfer', 'loveme'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), buy_ram=object()), 'buyram', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object()), 'buyram', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), buy_ram_bytes=object()), 'buyrambytes', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), sell_ram=object()), 'sellram', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), delegate=object()), 'delegatebw', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), undelegate=object()), 'undelegatebw', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), refund=object()), 'refund', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object()), 'refund', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), vote_producer=object()), 'voteproducer', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), update_auth=object()), 'updateauth', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), delete_auth=object()), 'deleteauth', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), link_auth=object()), 'linkauth', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), unlink_auth=object()), 'unlinkauth', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object()), 'unlinkauth', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), new_account=object()), 'newaccount', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), transfer=object()), 'transfer', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object()), 'unknown', 'not_eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), buy_ram=object()), 'test', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), unknown=[]), 'buyram', 'eosio'), False) + self.assertEqual(check_action(EosTxActionAck(common=object(), unknown=[]), 'transfer', 'loveme'), False) if __name__ == '__main__': diff --git a/core/tests/test_apps.nem.mosaic.py b/core/tests/test_apps.nem.mosaic.py index 8f224fd5d..e84d66a35 100644 --- a/core/tests/test_apps.nem.mosaic.py +++ b/core/tests/test_apps.nem.mosaic.py @@ -7,13 +7,21 @@ if not utils.BITCOIN_ONLY: from apps.nem.transfer.serialize import * +def get_mosaic(namespace: str, quantity: int, mosaic: str) -> NEMMosaic: + return NEMMosaic( + namespace=namespace, + quantity=quantity, + mosaic=mosaic, + ) + + @unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin") class TestNemMosaic(unittest.TestCase): def test_get_mosaic_definition(self): m = get_mosaic_definition("nem", "xem", 104) - self.assertEqual(m["name"], "NEM") - self.assertEqual(m["ticker"], " XEM") + self.assertEqual(m.name, "NEM") + self.assertEqual(m.ticker, " XEM") m = get_mosaic_definition("nem", "xxx", 104) self.assertEqual(m, None) @@ -22,39 +30,18 @@ class TestNemMosaic(unittest.TestCase): self.assertEqual(m, None) m = get_mosaic_definition("pacnem", "cheese", 104) - self.assertEqual(m["name"], "PacNEM Score Tokens") - self.assertEqual(m["ticker"], " PAC:CHS") - self.assertEqual(m["fee"], 100) + self.assertEqual(m.name, "PacNEM Score Tokens") + self.assertEqual(m.ticker, " PAC:CHS") + self.assertEqual(m.levy.fee, 100) def test_mosaic_canonicalization(self): - a = NEMMosaic() - a.namespace = 'abc' - a.quantity = 3 - a.mosaic = 'mosaic' - b = NEMMosaic() - b.namespace = 'abc' - b.quantity = 4 - b.mosaic = 'a' - c = NEMMosaic() - c.namespace = 'zzz' - c.quantity = 3 - c.mosaic = 'mosaic' - d = NEMMosaic() - d.namespace = 'abc' - d.quantity = 8 - d.mosaic = 'mosaic' - e = NEMMosaic() - e.namespace = 'aaa' - e.quantity = 1 - e.mosaic = 'mosaic' - f = NEMMosaic() - f.namespace = 'aaa' - f.quantity = 1 - f.mosaic = 'mosaicz' - g = NEMMosaic() - g.namespace = 'zzz' - g.quantity = 30 - g.mosaic = 'mosaic' + a = get_mosaic("abc", 3, "mosaic") + b = get_mosaic("abc", 4, "a") + c = get_mosaic("zzz", 3, "mosaic") + d = get_mosaic("abc", 8, "mosaic") + e = get_mosaic("aaa", 1, "mosaic") + f = get_mosaic("aaa", 1, "mosaicz") + g = get_mosaic("zzz", 30, "mosaic") res = canonicalize_mosaics([a, b, c, d, e, f, g]) self.assertEqual(res, [e, f, b, a, c]) @@ -63,14 +50,9 @@ class TestNemMosaic(unittest.TestCase): self.assertEqual(res[4].quantity, 3 + 30) # c + g def test_mosaic_merge(self): - a = NEMMosaic() - a.namespace = 'abc' - a.quantity = 1 - a.mosaic = 'mosaic' - b = NEMMosaic() - b.namespace = 'abc' - b.quantity = 1 - b.mosaic = 'mosaic' + a = get_mosaic("abc", 1, "mosaic") + b = get_mosaic("abc", 1, "mosaic") + c = get_mosaic("abc", 2, "xxx") merged = merge_mosaics([a, b]) self.assertEqual(merged[0].quantity, 2) @@ -81,88 +63,77 @@ class TestNemMosaic(unittest.TestCase): merged = merge_mosaics([a, b]) self.assertEqual(merged[0].quantity, 11) - a.namespace = 'abcdef' + a.namespace = "abcdef" merged = merge_mosaics([a, b]) self.assertEqual(len(merged), 2) - c = NEMMosaic() - c.namespace = 'abc' - c.mosaic = 'xxx' - c.quantity = 2 merged = merge_mosaics([a, b, c]) self.assertEqual(len(merged), 3) - a.namespace = 'abcdef' + a.namespace = "abcdef" a.quantity = 1 - a.mosaic = 'mosaic' - b.namespace = 'abc' + a.mosaic = "mosaic" + b.namespace = "abc" b.quantity = 2 - b.mosaic = 'mosaic' - c.namespace = 'abc' - c.mosaic = 'mosaic' + b.mosaic = "mosaic" + c.namespace = "abc" + c.mosaic = "mosaic" c.quantity = 3 merged = merge_mosaics([a, b, c]) self.assertEqual(merged[0].quantity, 1) self.assertEqual(merged[1].quantity, 5) self.assertEqual(len(merged), 2) - a.namespace = 'abc' + a.namespace = "abc" a.quantity = 1 - a.mosaic = 'mosaic' - b.namespace = 'abc' + a.mosaic = "mosaic" + b.namespace = "abc" b.quantity = 2 - b.mosaic = 'mosaic' - c.namespace = 'abc' - c.mosaic = 'mosaic' + b.mosaic = "mosaic" + c.namespace = "abc" + c.mosaic = "mosaic" c.quantity = 3 merged = merge_mosaics([a, b, c]) self.assertEqual(merged[0].quantity, 6) self.assertEqual(len(merged), 1) def test_mosaic_sort(self): - a = NEMMosaic() - a.namespace = 'abcz' - a.quantity = 1 - a.mosaic = 'mosaic' - b = NEMMosaic() - b.namespace = 'abca' - b.quantity = 1 - b.mosaic = 'mosaic' + a = get_mosaic("abcz", 1, "mosaic") + b = get_mosaic("abca", 1, "mosaic") + c = get_mosaic("a", 0, "zzz") + res = sort_mosaics([a, b]) self.assertListEqual(res, [b, a]) - a.namespace = '' - b.namespace = 'a.b.c' + a.namespace = "" + b.namespace = "a.b.c" res = sort_mosaics([a, b]) self.assertListEqual(res, [a, b]) - a.namespace = 'z.z.z' - b.namespace = 'a.b.c' + a.namespace = "z.z.z" + b.namespace = "a.b.c" res = sort_mosaics([a, b]) self.assertListEqual(res, [b, a]) - a.namespace = 'a' - b.namespace = 'a' - a.mosaic = 'mosaic' - b.mosaic = 'mosaic' + a.namespace = "a" + b.namespace = "a" + a.mosaic = "mosaic" + b.mosaic = "mosaic" res = sort_mosaics([a, b]) self.assertListEqual(res, [a, b]) - a.mosaic = 'www' - b.mosaic = 'aaa' + a.mosaic = "www" + b.mosaic = "aaa" res = sort_mosaics([a, b]) self.assertListEqual(res, [b, a]) - c = NEMMosaic() - c.namespace = 'a' - c.mosaic = 'zzz' res = sort_mosaics([a, b, c]) self.assertListEqual(res, [b, a, c]) - c.mosaic = 'bbb' + c.mosaic = "bbb" res = sort_mosaics([a, b, c]) self.assertListEqual(res, [b, c, a]) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/core/tests/test_apps.nem.mosaic_creation.py b/core/tests/test_apps.nem.mosaic_creation.py index ab63b6bb7..c05849610 100644 --- a/core/tests/test_apps.nem.mosaic_creation.py +++ b/core/tests/test_apps.nem.mosaic_creation.py @@ -125,31 +125,36 @@ def _create_msg(network: int, timestamp: int, fee: int, deadline: int, divisibility: int, supply: int, mutable_supply: bool, transferable: bool, levy_type: int, levy_fee: int, levy_address: str, levy_namespace: str, levy_mosaic: str, creation_sink: str, creation_fee: int): - m = NEMSignTx() - m.transaction = NEMTransactionCommon() - m.transaction.network = network - m.transaction.timestamp = timestamp - m.transaction.fee = fee - m.transaction.deadline = deadline - - m.mosaic_creation = NEMMosaicCreation() - m.mosaic_creation.sink = creation_sink - m.mosaic_creation.fee = creation_fee - - m.mosaic_creation.definition = NEMMosaicDefinition() - m.mosaic_creation.definition.namespace = namespace - m.mosaic_creation.definition.mosaic = mosaic - m.mosaic_creation.definition.description = description - m.mosaic_creation.definition.divisibility = divisibility - m.mosaic_creation.definition.supply = supply - m.mosaic_creation.definition.mutable_supply = mutable_supply - m.mosaic_creation.definition.transferable = transferable - m.mosaic_creation.definition.levy = levy_type - m.mosaic_creation.definition.fee = levy_fee - m.mosaic_creation.definition.levy_address = levy_address - m.mosaic_creation.definition.levy_namespace = levy_namespace - m.mosaic_creation.definition.levy_mosaic = levy_mosaic - return m + transaction = NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) + + mosaic_creation = NEMMosaicCreation( + sink=creation_sink, + fee=creation_fee, + definition=NEMMosaicDefinition( + namespace=namespace, + mosaic=mosaic, + description=description, + divisibility=divisibility, + supply=supply, + mutable_supply=mutable_supply, + transferable=transferable, + levy=levy_type, + fee=levy_fee, + levy_address=levy_address, + levy_namespace=levy_namespace, + levy_mosaic=levy_mosaic, + ) + ) + + return NEMSignTx( + transaction=transaction, + mosaic_creation=mosaic_creation, + ) if __name__ == '__main__': diff --git a/core/tests/test_apps.nem.mosaic_supply_change.py b/core/tests/test_apps.nem.mosaic_supply_change.py index 465871d38..4ee9ac366 100644 --- a/core/tests/test_apps.nem.mosaic_supply_change.py +++ b/core/tests/test_apps.nem.mosaic_supply_change.py @@ -74,19 +74,24 @@ class TestNemMosaicSupplyChange(unittest.TestCase): def _create_msg(network: int, timestamp: int, fee: int, deadline: int, namespace: str, mosaic: str, mod_type: int, delta: int): - m = NEMSignTx() - m.transaction = NEMTransactionCommon() - m.transaction.network = network - m.transaction.timestamp = timestamp - m.transaction.fee = fee - m.transaction.deadline = deadline - - m.supply_change = NEMMosaicSupplyChange() - m.supply_change.namespace = namespace - m.supply_change.mosaic = mosaic - m.supply_change.type = mod_type - m.supply_change.delta = delta - return m + transaction = NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) + + supply_change = NEMMosaicSupplyChange( + namespace=namespace, + mosaic=mosaic, + type=mod_type, + delta=delta, + ) + + return NEMSignTx( + transaction=transaction, + supply_change=supply_change, + ) if __name__ == '__main__': diff --git a/core/tests/test_apps.nem.multisig.aggregate_modification.py b/core/tests/test_apps.nem.multisig.aggregate_modification.py index 1058f7e1b..a89311c6a 100644 --- a/core/tests/test_apps.nem.multisig.aggregate_modification.py +++ b/core/tests/test_apps.nem.multisig.aggregate_modification.py @@ -156,18 +156,22 @@ def _create_msg( modifications: int, relative_change: int, ): - m = NEMSignTx() - m.transaction = NEMTransactionCommon() - m.transaction.network = network - m.transaction.timestamp = timestamp - m.transaction.fee = fee - m.transaction.deadline = deadline - - m.aggregate_modification = NEMAggregateModification() - for i in range(modifications): - m.aggregate_modification.modifications.append(NEMCosignatoryModification()) - m.aggregate_modification.relative_change = relative_change - return m + transaction = NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) + + aggregate_modification = NEMAggregateModification( + modifications=[NEMCosignatoryModification(type=5, public_key=b"abc") for _ in range(modifications)], + relative_change=relative_change + ) + + return NEMSignTx( + transaction=transaction, + aggregate_modification=aggregate_modification, + ) if __name__ == "__main__": diff --git a/core/tests/test_apps.nem.multisig.py b/core/tests/test_apps.nem.multisig.py index 34982e855..af2255a0a 100644 --- a/core/tests/test_apps.nem.multisig.py +++ b/core/tests/test_apps.nem.multisig.py @@ -25,7 +25,7 @@ class TestNemMultisig(unittest.TestCase): 0) base_tx = serialize_aggregate_modification(m.transaction, m.aggregate_modification, unhexlify("abac2ee3d4aaa7a3bfb65261a00cc04c761521527dd3f2cf741e2815cbba83ac")) - base_tx = write_cosignatory_modification(base_tx, 2, unhexlify("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3")) + write_cosignatory_modification(base_tx, 2, unhexlify("e6cff9b3725a91f31089c3acca0fac3e341c00b1c8c6e9578f66c4514509c3b3")) m = _create_common_msg(NEM_NETWORK_TESTNET, 3939039, 6000000, @@ -80,37 +80,41 @@ class TestNemMultisig(unittest.TestCase): def _create_common_msg(network: int, timestamp: int, fee: int, deadline: int): - m = NEMTransactionCommon() - m.network = network - m.timestamp = timestamp - m.fee = fee - m.deadline = deadline - return m + return NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) def _create_msg(network: int, timestamp: int, fee: int, deadline: int, modifications: int, relative_change: int): - m = NEMSignTx() - m.transaction = _create_common_msg(network, timestamp, fee, deadline) + aggregate_modification = NEMAggregateModification( + modifications=[NEMCosignatoryModification(type=5, public_key=b"abc") for _ in range(modifications)], + relative_change=relative_change + ) - m.aggregate_modification = NEMAggregateModification() - for i in range(modifications): - m.aggregate_modification.modifications.append(NEMCosignatoryModification()) - m.aggregate_modification.relative_change = relative_change - return m + return NEMSignTx( + transaction=_create_common_msg(network, timestamp, fee, deadline), + aggregate_modification=aggregate_modification, + ) def _create_provision_msg(network: int, timestamp: int, fee: int, deadline: int, name: str, parent: str, sink: str, rental_fee: int): - m = NEMSignTx() - m.transaction = _create_common_msg(network, timestamp, fee, deadline) - - m.provision_namespace = NEMProvisionNamespace() - m.provision_namespace.namespace = name - m.provision_namespace.parent = parent - m.provision_namespace.sink = sink - m.provision_namespace.fee = rental_fee - return m + provision_namespace = NEMProvisionNamespace( + namespace=name, + parent=parent, + sink=sink, + fee=rental_fee, + ) + + return NEMSignTx( + transaction=_create_common_msg(network, timestamp, fee, deadline), + provision_namespace=provision_namespace, + ) + if __name__ == '__main__': diff --git a/core/tests/test_apps.nem.namespace.py b/core/tests/test_apps.nem.namespace.py index 722d6c494..0cd9ddf1b 100644 --- a/core/tests/test_apps.nem.namespace.py +++ b/core/tests/test_apps.nem.namespace.py @@ -56,18 +56,24 @@ class TestNemNamespace(unittest.TestCase): def _create_msg(network: int, timestamp: int, fee: int, deadline: int, name: str, parent: str, sink: str, rental_fee: int): - m = NEMSignTx() - m.transaction = NEMTransactionCommon() - m.transaction.network = network - m.transaction.timestamp = timestamp - m.transaction.fee = fee - m.transaction.deadline = deadline - m.provision_namespace = NEMProvisionNamespace() - m.provision_namespace.namespace = name - m.provision_namespace.parent = parent - m.provision_namespace.sink = sink - m.provision_namespace.fee = rental_fee - return m + transaction = NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) + + provision_namespace = NEMProvisionNamespace( + namespace=name, + parent=parent, + sink=sink, + fee=rental_fee, + ) + + return NEMSignTx( + transaction=transaction, + provision_namespace=provision_namespace, + ) if __name__ == '__main__': diff --git a/core/tests/test_apps.nem.transfer.py b/core/tests/test_apps.nem.transfer.py index 8300a9fe1..e9a1d4025 100644 --- a/core/tests/test_apps.nem.transfer.py +++ b/core/tests/test_apps.nem.transfer.py @@ -24,7 +24,7 @@ class TestNemTransfer(unittest.TestCase): 'TBGIMRE4SBFRUJXMH7DVF2IBY36L2EDWZ37GVSC4', 50000000000000) - t = serialize_transfer(m.transaction, m.transfer, unhexlify('e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f')) + t = serialize_transfer(m.transaction, m.transfer, unhexlify('e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f'), None, False) self.assertEqual(t, unhexlify('01010000010000980000000020000000e59ef184a612d4c3c4d89b5950eb57262c69862b2f96e59c5043bf41765c482f00000000000000000000000028000000544247494d52453453424652554a584d48374456463249425933364c324544575a3337475653433400203d88792d000000000000')) self.assertEqual(hashlib.sha3_256(t, keccak=True).digest(), unhexlify('0acbf8df91e6a65dc56c56c43d65f31ff2a6a48d06fc66e78c7f3436faf3e74f')) @@ -40,7 +40,8 @@ class TestNemTransfer(unittest.TestCase): t = serialize_transfer(m.transaction, m.transfer, unhexlify('8d07f90fb4bbe7715fa327c926770166a11be2e494a970605f2e12557f66c9b9'), - bytearray('Good luck!')) + bytearray('Good luck!'), + False) self.assertEqual(hashlib.sha3_256(t, keccak=True).digest(), unhexlify('e90e98614c7598fbfa4db5411db1b331d157c2f86b558fb7c943d013ed9f71cb')) def test_create_transfer_with_encrypted_payload(self): @@ -102,19 +103,23 @@ class TestNemTransfer(unittest.TestCase): def _create_msg(network: int, timestamp: int, fee: int, deadline: int, recipient: str, amount: int, mosaics: int = 0): - m = NEMSignTx() - m.transaction = NEMTransactionCommon() - m.transaction.network = network - m.transaction.timestamp = timestamp - m.transaction.fee = fee - m.transaction.deadline = deadline - m.transfer = NEMTransfer() - m.transfer.recipient = recipient - m.transfer.amount = amount - m.transfer.mosaics = list() - for i in range(mosaics): - m.transfer.mosaics.append(NEMMosaic()) - return m + transaction = NEMTransactionCommon( + network=network, + timestamp=timestamp, + fee=fee, + deadline=deadline, + ) + + transfer = NEMTransfer( + recipient=recipient, + amount=amount, + mosaics=[NEMMosaic(namespace="abc", quantity=5, mosaic="mosaic") for _ in range(mosaics)], + ) + + return NEMSignTx( + transaction=transaction, + transfer=transfer, + ) if __name__ == '__main__': diff --git a/core/tests/test_apps.ripple.serializer.py b/core/tests/test_apps.ripple.serializer.py index 85852f2a2..2a8272c56 100644 --- a/core/tests/test_apps.ripple.serializer.py +++ b/core/tests/test_apps.ripple.serializer.py @@ -36,7 +36,7 @@ class TestRippleSerializer(unittest.TestCase): payment=payment, ) self.assertEqual( - serialize(common, source_address), + serialize(common, source_address, pubkey=None), unhexlify( "120000240000000161400000000bebc20068400000000000000a811450f97a072f1c4357f1ad84566a609479d927c9428314550fc62003e785dc231a1058a05e56e3f09cf4e6" ), @@ -55,7 +55,7 @@ class TestRippleSerializer(unittest.TestCase): payment=payment, ) self.assertEqual( - serialize(common, source_address), + serialize(common, source_address, pubkey=None), unhexlify( "12000024000000636140000000000000016840000000000000638114550fc62003e785dc231a1058a05e56e3f09cf4e6831450f97a072f1c4357f1ad84566a609479d927c942" ), @@ -75,7 +75,7 @@ class TestRippleSerializer(unittest.TestCase): payment=payment, ) self.assertEqual( - serialize(common, source_address), + serialize(common, source_address, pubkey=None), unhexlify( "120000220000000024000000026140000000017d784068400000000000000a81145ccb151f6e9d603f394ae778acf10d3bece874f68314e851bbbe79e328e43d68f43445368133df5fba5a" ), @@ -96,7 +96,7 @@ class TestRippleSerializer(unittest.TestCase): ) # 201b005ee9ba removed from the test vector because last ledger sequence is not supported self.assertEqual( - serialize(common, source_address), + serialize(common, source_address, pubkey=None), unhexlify( "12000022000000002400000090614000000000030d4068400000000000000f8114aa1bd19d9e87be8069fdbf6843653c43837c03c6831467fe6ec28e0464dd24fb2d62a492aac697cfad02" ), @@ -118,7 +118,7 @@ class TestRippleSerializer(unittest.TestCase): payment=payment, ) self.assertEqual( - serialize(common, source_address), + serialize(common, source_address, pubkey=None), unhexlify( "120000220000000024000000012ef72d50ca6140000000017d784068400000000000000c8114e851bbbe79e328e43d68f43445368133df5fba5a831476dac5e814cd4aa74142c3ab45e69a900e637aa2" ), diff --git a/core/tests/test_storage.cache.py b/core/tests/test_storage.cache.py index 5337685f8..95aa8d682 100644 --- a/core/tests/test_storage.cache.py +++ b/core/tests/test_storage.cache.py @@ -102,13 +102,6 @@ class TestStorageCache(unittest.TestCase): cache.start_session(session_id1) self.assertEqual(cache.get(KEY), b"hello") - def test_decorator_mismatch(self): - with self.assertRaises(AssertionError): - - @cache.stored(KEY) - async def async_fun(): - pass - def test_decorators(self): run_count = 0 cache.start_session() diff --git a/core/tests/test_trezor.protobuf.py b/core/tests/test_trezor.protobuf.py index 03e94a68c..7f0c63288 100644 --- a/core/tests/test_trezor.protobuf.py +++ b/core/tests/test_trezor.protobuf.py @@ -1,7 +1,7 @@ from common import * from trezor import protobuf -from trezor.messages import WebAuthnCredential, EosAsset, Failure, SignMessage +from trezor.messages import WebAuthnCredential, Failure, SignMessage, DebugLinkMemoryRead def load_uvarint32(data: bytes) -> int: @@ -18,8 +18,8 @@ def load_uvarint64(data: bytes) -> int: buffer = bytearray(len(data) + 1) buffer[1:] = data buffer[0] = (2 << 3) | 0 # field number 1, wire type 0 - msg = protobuf.decode(buffer, EosAsset, False) - return msg.symbol + msg = protobuf.decode(buffer, DebugLinkMemoryRead, False) + return msg.length def dump_uvarint32(value: int) -> bytearray: @@ -34,7 +34,7 @@ def dump_uvarint32(value: int) -> bytearray: def dump_uvarint64(value: int) -> bytearray: # use known uint64 field in an all-optional message - msg = EosAsset(symbol=value) + msg = DebugLinkMemoryRead(length=value) length = protobuf.encoded_length(msg) buffer = bytearray(length) protobuf.encode(buffer, msg)