feat(core/cardano): enable typing for Cardano app

pull/1423/head
matejcik 3 years ago committed by matejcik
parent 32c37aa9cd
commit ccd241fe55

@ -44,9 +44,9 @@ enum CardanoPoolRelayType {
* @embed
*/
message CardanoBlockchainPointerType {
optional uint32 block_index = 1;
optional uint32 tx_index = 2;
optional uint32 certificate_index = 3;
required uint32 block_index = 1;
required uint32 tx_index = 2;
required uint32 certificate_index = 3;
}
/**
@ -58,7 +58,7 @@ message CardanoBlockchainPointerType {
* @embed
*/
message CardanoAddressParametersType {
optional CardanoAddressType address_type = 1; // one of the CardanoAddressType-s
required CardanoAddressType address_type = 1; // one of the CardanoAddressType-s
repeated uint32 address_n = 2; // BIP-32-style path to derive the spending key from master node
repeated uint32 address_n_staking = 3; // BIP-32-style path to derive staking key from master node
optional bytes staking_key_hash = 4; // staking key can be derived from address_n_staking, or
@ -75,10 +75,10 @@ message CardanoAddressParametersType {
*/
message CardanoGetAddress {
// repeated uint32 address_n = 1; // moved to address_parameters
optional bool show_display = 2; // optionally prompt for confirmation on trezor display
optional uint32 protocol_magic = 3; // network's protocol magic - needed for Byron addresses on testnets
optional uint32 network_id = 4; // network id - mainnet or testnet
optional CardanoAddressParametersType address_parameters = 5; // parameters used to derive the address
optional bool show_display = 2 [default=false]; // optionally prompt for confirmation on trezor display
required uint32 protocol_magic = 3; // network's protocol magic - needed for Byron addresses on testnets
required uint32 network_id = 4; // network id - mainnet or testnet
required CardanoAddressParametersType address_parameters = 5; // parameters used to derive the address
}
/**
@ -86,7 +86,7 @@ message CardanoGetAddress {
* @end
*/
message CardanoAddress {
optional string address = 1; // Base58 cardano address
required string address = 1; // Base58 cardano address
}
/**
@ -105,8 +105,8 @@ message CardanoGetPublicKey {
* @end
*/
message CardanoPublicKey {
optional string xpub = 1; // Xpub key
optional hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 public node
required string xpub = 1; // Xpub key
required hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 public node
}
/**
@ -119,10 +119,10 @@ message CardanoSignTx {
repeated CardanoTxInputType inputs = 1; // inputs to be used in transaction
repeated CardanoTxOutputType outputs = 2; // outputs to be used in transaction
// optional uint32 transactions_count = 3; // left as a comment so we know to skip the id 3 in the future
optional uint32 protocol_magic = 5; // network's protocol magic
optional uint64 fee = 6; // transaction fee - added in shelley
required uint32 protocol_magic = 5; // network's protocol magic
required uint64 fee = 6; // transaction fee - added in shelley
optional uint64 ttl = 7; // transaction ttl - added in shelley
optional uint32 network_id = 8; // network id - mainnet or testnet
required uint32 network_id = 8; // network id - mainnet or testnet
repeated CardanoTxCertificateType certificates = 9; // transaction certificates - added in shelley
repeated CardanoTxWithdrawalType withdrawals = 10; // transaction withdrawals - added in shelley
optional bytes metadata = 11; // transaction metadata - added in shelley
@ -133,8 +133,8 @@ message CardanoSignTx {
*/
message CardanoTxInputType {
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
optional bytes prev_hash = 2; // hash of previous transaction output to spend by this input
optional uint32 prev_index = 3; // index of previous output to spend
required bytes prev_hash = 2; // hash of previous transaction output to spend by this input
required uint32 prev_index = 3; // index of previous output to spend
// left as a comment so we know to skip the id 4 in the future
// optional uint32 type = 4;
}
@ -144,7 +144,7 @@ message CardanoSignTx {
message CardanoTxOutputType {
optional string address = 1; // target coin address in bech32 or base58
// repeated uint32 address_n = 2; // moved to address_parameters
optional uint64 amount = 3; // amount to spend
required uint64 amount = 3; // amount to spend
optional CardanoAddressParametersType address_parameters = 4; // parameters used to derive the address
repeated CardanoAssetGroupType token_bundle = 5; // custom assets - added in mary
}
@ -206,7 +206,7 @@ message CardanoSignTx {
* Structure representing cardano transaction certificate
*/
message CardanoTxCertificateType {
optional CardanoCertificateType type = 1; // certificate type
required CardanoCertificateType type = 1; // certificate type
repeated uint32 path = 2; // BIP-32 path to derive (staking) key
optional bytes pool = 3; // pool hash
optional CardanoPoolParametersType pool_parameters = 4; // used for stake pool registration certificate
@ -216,7 +216,7 @@ message CardanoSignTx {
*/
message CardanoTxWithdrawalType {
repeated uint32 path = 1;
optional uint64 amount = 2;
required uint64 amount = 2;
}
}
@ -225,6 +225,6 @@ message CardanoSignTx {
* @end
*/
message CardanoSignedTx {
optional bytes tx_hash = 1; // hash of the transaction body
optional bytes serialized_tx = 2; // serialized, signed transaction
required bytes tx_hash = 1; // hash of the transaction body
required bytes serialized_tx = 2; // serialized, signed transaction
}

@ -107,6 +107,7 @@ mypy:
mypy --config-file ../setup.cfg \
src/main.py \
src/apps/bitcoin \
src/apps/cardano \
src/apps/webauthn
## code generation:

@ -586,7 +586,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_bip32_from_seed_obj,
#if !BITCOIN_ONLY
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes:
/// def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> HDNode:
/// """
/// Construct a HD node from a BIP-0039 mnemonic using the Icarus derivation
/// scheme, aka v2 derivation scheme.

@ -117,7 +117,7 @@ def from_seed(seed: bytes, curve_name: str) -> HDNode:
# extmod/modtrezorcrypto/modtrezorcrypto-bip32.h
def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> bytes:
def from_mnemonic_cardano(mnemonic: str, passphrase: str) -> HDNode:
"""
Construct a HD node from a BIP-0039 mnemonic using the Icarus derivation
scheme, aka v2 derivation scheme.

@ -1,6 +1,6 @@
from trezor import wire
from trezor.crypto import base58, hashlib
from trezor.messages import CardanoAddressParametersType, CardanoAddressType
from trezor.messages import CardanoAddressType
from apps.common.seed import remove_ed25519_prefix
@ -11,9 +11,14 @@ from .helpers.utils import variable_length_encode
from .seed import is_byron_path, is_shelley_path
if False:
from typing import List
from trezor.messages import CardanoBlockchainPointerType
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
from typing import List, Optional
from trezor.messages.CardanoBlockchainPointerType import (
CardanoBlockchainPointerType,
)
from trezor.messages.CardanoAddressParametersType import (
CardanoAddressParametersType,
EnumTypeCardanoAddressType,
)
from . import seed
ADDRESS_TYPES_SHELLEY = (
@ -84,8 +89,8 @@ def get_address_bytes_unsafe(address: str) -> bytes:
return address_bytes
def _get_address_type(address: bytes) -> int:
return address[0] >> 4
def _get_address_type(address: bytes) -> EnumTypeCardanoAddressType:
return address[0] >> 4 # type: ignore
def _validate_shelley_address(
@ -93,14 +98,12 @@ def _validate_shelley_address(
) -> None:
address_type = _get_address_type(address_bytes)
_validate_address_size(address_bytes, address_type)
_validate_address_size(address_bytes)
_validate_address_bech32_hrp(address_str, address_type, network_id)
_validate_address_network_id(address_bytes, network_id)
def _validate_address_size(
address_bytes: bytes, address_type: EnumTypeCardanoAddressType
) -> None:
def _validate_address_size(address_bytes: bytes) -> None:
if not (MIN_ADDRESS_BYTES_LENGTH <= len(address_bytes) <= MAX_ADDRESS_BYTES_LENGTH):
raise INVALID_ADDRESS
@ -220,6 +223,8 @@ def _derive_shelley_address(
elif parameters.address_type == CardanoAddressType.ENTERPRISE:
address = _derive_enterprise_address(keychain, parameters.address_n, network_id)
elif parameters.address_type == CardanoAddressType.POINTER:
if parameters.certificate_pointer is None:
raise wire.DataError("Certificate pointer data missing!")
address = _derive_pointer_address(
keychain,
parameters.address_n,
@ -245,7 +250,7 @@ def _derive_base_address(
keychain: seed.Keychain,
path: List[int],
staking_path: List[int],
staking_key_hash: bytes,
staking_key_hash: Optional[bytes],
network_id: int,
) -> bytes:
header = _create_address_header(CardanoAddressType.BASE, network_id)
@ -261,7 +266,7 @@ def _derive_base_address(
def _validate_base_address_staking_info(
staking_path: List[int],
staking_key_hash: bytes,
staking_key_hash: Optional[bytes],
) -> None:
if (staking_key_hash is None) == (not staking_path):
raise wire.DataError(
@ -286,14 +291,6 @@ def _derive_pointer_address(
def _encode_certificate_pointer(pointer: CardanoBlockchainPointerType) -> bytes:
if (
pointer is None
or pointer.block_index is None
or pointer.tx_index is None
or pointer.certificate_index is None
):
raise wire.DataError("Invalid pointer!")
block_index_encoded = variable_length_encode(pointer.block_index)
tx_index_encoded = variable_length_encode(pointer.tx_index)
certificate_index_encoded = variable_length_encode(pointer.certificate_index)

@ -21,7 +21,7 @@ with base58 encoding and all the nuances of Byron addresses.
"""
def _encode_address_raw(address_data_encoded) -> bytes:
def _encode_address_raw(address_data_encoded: bytes) -> bytes:
return cbor.encode(
[cbor.Tagged(24, address_data_encoded), crc.crc32(address_data_encoded)]
)

@ -11,6 +11,8 @@ from .helpers import INVALID_CERTIFICATE, LOVELACE_MAX_SUPPLY
from .helpers.paths import SCHEMA_STAKING
if False:
from typing import List, Optional
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
from trezor.messages.CardanoPoolParametersType import CardanoPoolParametersType
from trezor.messages.CardanoPoolRelayParametersType import (
@ -18,10 +20,10 @@ if False:
)
from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType
from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType
from typing import List, Optional, Union, Tuple, Any
from . import seed
CborSequence = Union[List[Any], Tuple[Any, ...]]
from apps.common.cbor import CborSequence
from . import seed
POOL_HASH_SIZE = 28
VRF_KEY_HASH_SIZE = 32

@ -17,7 +17,10 @@ from .layout import (
from .sign_tx import validate_network_info
if False:
from trezor.messages import CardanoAddressParametersType, CardanoGetAddress
from trezor.messages.CardanoAddressParametersType import (
CardanoAddressParametersType,
)
from trezor.messages.CardanoGetAddress import CardanoGetAddress
@seed.with_keychain
@ -95,4 +98,6 @@ async def _show_staking_warnings(
address_parameters.staking_key_hash,
)
elif staking_type == staking_use_cases.POINTER_ADDRESS:
# ensured in _derive_shelley_address:
assert address_parameters.certificate_pointer is not None
await show_warning_address_pointer(ctx, address_parameters.certificate_pointer)

@ -12,13 +12,13 @@ from .helpers.paths import SCHEMA_PUBKEY
if False:
from typing import List
from trezor.messages import CardanoGetPublicKey
from trezor.messages.CardanoGetPublicKey import CardanoGetPublicKey
@seed.with_keychain
async def get_public_key(
ctx: wire.Context, msg: CardanoGetPublicKey, keychain: seed.Keychain
):
) -> CardanoPublicKey:
await paths.validate_path(
ctx,
keychain,

@ -10,6 +10,8 @@ HRP_TESTNET_REWARD_ADDRESS = "stake_test"
def encode(hrp: str, data: bytes) -> str:
converted_bits = bech32.convertbits(data, 8, 5)
if converted_bits is None:
raise ValueError
return bech32.bech32_encode(hrp, converted_bits)
@ -18,12 +20,14 @@ def decode_unsafe(bech: str) -> bytes:
return decode(hrp, bech)
def get_hrp(bech: str):
def get_hrp(bech: str) -> str:
return bech.rsplit(HRP_SEPARATOR, 1)[0]
def decode(hrp: str, bech: str) -> bytes:
decoded_hrp, data = bech32.bech32_decode(bech, 130)
if data is None:
raise ValueError
if decoded_hrp != hrp:
raise ValueError

@ -7,8 +7,10 @@ from .utils import to_account_path
if False:
from typing import List
from trezor.messages import CardanoAddressParametersType
from .. import seed
from trezor.messages.CardanoAddressParametersType import (
CardanoAddressParametersType,
)
from ..seed import Keychain
"""
@ -24,9 +26,7 @@ MISMATCH = 2
POINTER_ADDRESS = 3
def get(
keychain: seed.Keychain, address_parameters: CardanoAddressParametersType
) -> int:
def get(keychain: Keychain, address_parameters: CardanoAddressParametersType) -> int:
address_type = address_parameters.address_type
if address_type == CardanoAddressType.BASE:
if not SCHEMA_ADDRESS.match(address_parameters.address_n):

@ -6,8 +6,6 @@ from trezor.messages import (
ButtonRequestType,
CardanoAddressType,
CardanoCertificateType,
CardanoPoolMetadataType,
CardanoPoolOwnerType,
)
from trezor.strings import format_amount
from trezor.ui.button import ButtonDefault
@ -30,14 +28,16 @@ from .helpers.utils import format_account_number, format_optional_int, to_accoun
if False:
from typing import List, Optional
from trezor import wire
from trezor.messages import (
from trezor.messages.CardanoBlockchainPointerType import (
CardanoBlockchainPointerType,
CardanoTxCertificateType,
CardanoTxWithdrawalType,
CardanoPoolParametersType,
CardanoAssetGroupType,
CardanoTokenType,
)
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
from trezor.messages.CardanoPoolParametersType import CardanoPoolParametersType
from trezor.messages.CardanoPoolOwnerType import CardanoPoolOwnerType
from trezor.messages.CardanoPoolMetadataType import CardanoPoolMetadataType
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
from trezor.messages.CardanoTokenType import CardanoTokenType
from trezor.messages.CardanoAddressParametersType import EnumTypeCardanoAddressType
@ -85,7 +85,8 @@ async def confirm_sending(
to_lines = list(chunks(to, 17))
page1.bold(to_lines[0])
pages = [page1] + _paginate_lines(to_lines, 1, "Confirm transaction", ui.ICON_SEND)
comp: ui.Component = page1 # otherwise `[page1]` is of the wrong type
pages = [comp] + _paginate_lines(to_lines, 1, "Confirm transaction", ui.ICON_SEND)
await require_confirm(ctx, Paginated(pages))
@ -215,7 +216,7 @@ async def show_warning_tx_staking_key_hash(
async def confirm_transaction(
ctx,
ctx: wire.Context,
amount: int,
fee: int,
protocol_magic: int,
@ -224,7 +225,7 @@ async def confirm_transaction(
has_metadata: bool,
is_network_id_verifiable: bool,
) -> None:
pages = []
pages: List[ui.Component] = []
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Transaction amount:")
@ -257,7 +258,7 @@ async def confirm_certificate(
# in this call
assert certificate.type != CardanoCertificateType.STAKE_POOL_REGISTRATION
pages = []
pages: List[ui.Component] = []
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Confirm:")
@ -267,6 +268,7 @@ async def confirm_certificate(
pages.append(page1)
if certificate.type == CardanoCertificateType.STAKE_DELEGATION:
assert certificate.pool is not None # validate_certificate
page2 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page2.normal("to pool:")
page2.bold(hexlify(certificate.pool).decode())
@ -304,11 +306,11 @@ async def confirm_stake_pool_parameters(
async def confirm_stake_pool_owners(
ctx: wire.Context,
keychain: seed.keychain,
keychain: seed.Keychain,
owners: List[CardanoPoolOwnerType],
network_id: int,
) -> None:
pages = []
pages: List[ui.Component] = []
for index, owner in enumerate(owners, 1):
page = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page.normal("Pool owner #%d:" % (index))
@ -324,6 +326,7 @@ async def confirm_stake_pool_owners(
)
)
else:
assert owner.staking_key_hash is not None # validate_pool_owners
page.bold(
encode_human_readable_address(
pack_reward_address_bytes(owner.staking_key_hash, network_id)
@ -360,7 +363,10 @@ async def confirm_stake_pool_metadata(
async def confirm_transaction_network_ttl(
ctx, protocol_magic: int, ttl: Optional[int], validity_interval_start: Optional[int]
ctx: wire.Context,
protocol_magic: int,
ttl: Optional[int],
validity_interval_start: Optional[int],
) -> None:
page1 = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
page1.normal("Network:")
@ -428,13 +434,17 @@ async def show_address(
for address_line in address_lines[: lines_per_page - lines_used_on_first_page]:
page1.bold(address_line)
pages: List[ui.Component] = []
pages.append(page1)
# append remaining pages containing the rest of the address
pages = [page1] + _paginate_lines(
address_lines,
lines_per_page - lines_used_on_first_page,
address_type_label,
ui.ICON_RECEIVE,
lines_per_page,
pages.extend(
_paginate_lines(
address_lines,
lines_per_page - lines_used_on_first_page,
address_type_label,
ui.ICON_RECEIVE,
lines_per_page,
)
)
return await confirm(
@ -449,7 +459,7 @@ async def show_address(
def _paginate_lines(
lines: List[str], offset: int, desc: str, icon: str, lines_per_page: int = 4
) -> List[ui.Component]:
pages = []
pages: List[ui.Component] = []
if len(lines) > offset:
to_pages = list(chunks(lines[offset:], lines_per_page))
for page in to_pages:
@ -465,7 +475,7 @@ async def show_warning_address_foreign_staking_key(
ctx: wire.Context,
account_path: List[int],
staking_account_path: List[int],
staking_key_hash: bytes,
staking_key_hash: Optional[bytes],
) -> None:
page1 = Text("Warning", ui.ICON_WRONG, ui.RED)
page1.normal("Stake rights associated")
@ -480,6 +490,7 @@ async def show_warning_address_foreign_staking_key(
page2.bold(address_n_to_str(staking_account_path))
page2.br_half()
else:
assert staking_key_hash is not None # _validate_base_address_staking_info
page2.normal("Staking key:")
page2.bold(hexlify(staking_key_hash).decode())
page2.normal("Continue?")

@ -9,8 +9,12 @@ from apps.common.seed import get_seed
from .helpers import paths
if False:
from typing import Callable, Awaitable
from apps.common.paths import Bip32Path
from apps.common.keychain import MsgIn, MsgOut, Handler, HandlerWithKeychain
from apps.common.keychain import MsgIn, MsgOut, Handler
HandlerWithKeychain = Callable[[wire.Context, MsgIn, "Keychain"], Awaitable[MsgOut]]
class Keychain:
@ -52,11 +56,11 @@ class Keychain:
# self.root.__del__()
def is_byron_path(path: Bip32Path):
def is_byron_path(path: Bip32Path) -> bool:
return path[: len(paths.BYRON_ROOT)] == paths.BYRON_ROOT
def is_shelley_path(path: Bip32Path):
def is_shelley_path(path: Bip32Path) -> bool:
return path[: len(paths.SHELLEY_ROOT)] == paths.SHELLEY_ROOT
@ -75,7 +79,9 @@ async def get_keychain(ctx: wire.Context) -> Keychain:
if mnemonic.is_bip39():
passphrase = await get_passphrase(ctx)
# derive the root node from mnemonic and passphrase via Cardano Icarus algorithm
root = bip32.from_mnemonic_cardano(mnemonic.get_secret().decode(), passphrase)
secret_bytes = mnemonic.get_secret()
assert secret_bytes is not None
root = bip32.from_mnemonic_cardano(secret_bytes.decode(), passphrase)
else:
# derive the root node via SLIP-0023
seed = await get_seed(ctx)

@ -57,13 +57,16 @@ from .layout import (
from .seed import is_byron_path, is_shelley_path
if False:
from typing import Any, Dict, List, Optional, Tuple, Union
from trezor.messages.CardanoSignTx import CardanoSignTx
from trezor.messages.CardanoTxCertificateType import CardanoTxCertificateType
from trezor.messages.CardanoTxInputType import CardanoTxInputType
from trezor.messages.CardanoTxOutputType import CardanoTxOutputType
from trezor.messages.CardanoTxWithdrawalType import CardanoTxWithdrawalType
from trezor.messages.CardanoAssetGroupType import CardanoAssetGroupType
from typing import Dict, List, Tuple, Union
from apps.common.cbor import CborSequence
CborizedTokenBundle = Dict[bytes, Dict[bytes, int]]
CborizedTxOutput = Tuple[bytes, Union[int, Tuple[int, CborizedTokenBundle]]]
@ -156,7 +159,7 @@ async def _sign_stake_pool_registration_tx(
return tx
def _has_stake_pool_registration(msg: CardanoSignTx):
def _has_stake_pool_registration(msg: CardanoSignTx) -> bool:
return any(
cert.type == CardanoCertificateType.STAKE_POOL_REGISTRATION
for cert in msg.certificates
@ -176,7 +179,9 @@ def validate_network_info(network_id: int, protocol_magic: int) -> None:
raise wire.ProcessError("Invalid network id/protocol magic combination!")
def _validate_stake_pool_registration_tx_structure(msg: CardanoSignTx):
def _validate_stake_pool_registration_tx_structure(msg: CardanoSignTx) -> None:
# ensures that there is exactly one certificate, which is stake pool registration,
# and no withdrawals
if (
len(msg.certificates) != 1
or not _has_stake_pool_registration(msg)
@ -264,7 +269,7 @@ def _validate_max_tx_output_size(
)
def _ensure_no_signing_inputs(inputs: List[CardanoTxInputType]):
def _ensure_no_signing_inputs(inputs: List[CardanoTxInputType]) -> None:
if any(i.address_n for i in inputs):
raise INVALID_STAKEPOOL_REGISTRATION_TX_INPUTS
@ -285,7 +290,7 @@ def _validate_withdrawals(withdrawals: List[CardanoTxWithdrawalType]) -> None:
raise INVALID_WITHDRAWAL
def _validate_metadata(metadata: bytes) -> None:
def _validate_metadata(metadata: Optional[bytes]) -> None:
if not metadata:
return
@ -388,7 +393,7 @@ def _cborize_output(
keychain, output.address_parameters, protocol_magic, network_id
)
else:
# output address is validated in _validate_outputs before this happens
assert output.address is not None # _validate_outputs
address = get_address_bytes_unsafe(output.address)
if not output.token_bundle:
@ -400,11 +405,11 @@ def _cborize_output(
def _cborize_token_bundle(
token_bundle: List[CardanoAssetGroupType],
) -> CborizedTokenBundle:
result = {}
result: CborizedTokenBundle = {}
for token_group in token_bundle:
cborized_policy_id = bytes(token_group.policy_id)
result[cborized_policy_id] = cborized_token_group = {}
cborized_token_group = result[cborized_policy_id] = {}
for token in token_group.tokens:
cborized_asset_name = bytes(token.asset_name_bytes)
@ -416,7 +421,7 @@ def _cborize_token_bundle(
def _cborize_certificates(
keychain: seed.Keychain,
certificates: List[CardanoTxCertificateType],
) -> List[Tuple]:
) -> List[CborSequence]:
return [cborize_certificate(keychain, cert) for cert in certificates]
@ -469,7 +474,7 @@ def _cborize_witnesses(
# use key 0 for shelley witnesses and key 2 for byron witnesses
# according to the spec in shelley.cddl in cardano-ledger-specs
witnesses = {}
witnesses: Dict[Any, Any] = {}
if shelley_witnesses:
witnesses[0] = shelley_witnesses
if byron_witnesses:
@ -499,6 +504,8 @@ def _cborize_shelley_witnesses(
):
paths.add(tuple(certificate.path))
elif certificate.type == CardanoCertificateType.STAKE_POOL_REGISTRATION:
# ensured by validate_certificate:
assert certificate.pool_parameters is not None # validate_certificate
for pool_owner in certificate.pool_parameters.owners:
if pool_owner.staking_key_path:
paths.add(tuple(pool_owner.staking_key_path))
@ -514,7 +521,7 @@ def _cborize_shelley_witnesses(
def _cborize_shelley_witness(
keychain: seed.Keychain, tx_body_hash: bytes, path: List[int]
) -> List[Tuple[bytes, bytes]]:
) -> Tuple[bytes, bytes]:
node = keychain.derive(path)
signature = ed25519.sign_ext(
@ -587,6 +594,9 @@ async def _show_stake_pool_registration_tx(
) -> None:
stake_pool_registration_certificate = msg.certificates[0]
pool_parameters = stake_pool_registration_certificate.pool_parameters
# _validate_stake_pool_registration_tx_structure ensures that there is only one
# certificate, and validate_certificate ensures that the structure is valid
assert pool_parameters is not None
# display the transaction (certificate) in UI
await confirm_stake_pool_parameters(
@ -619,6 +629,7 @@ async def _show_outputs(
if _should_hide_output(output.address_parameters.address_n, msg.inputs):
continue
else:
assert output.address is not None # _validate_outputs
address = output.address
total_amount += output.amount
@ -637,13 +648,15 @@ async def _show_change_output_staking_warnings(
address_parameters: CardanoAddressParametersType,
address: str,
amount: int,
):
) -> None:
address_type = address_parameters.address_type
staking_use_case = staking_use_cases.get(keychain, address_parameters)
if staking_use_case == staking_use_cases.NO_STAKING:
await show_warning_tx_no_staking_info(ctx, address_type, amount)
elif staking_use_case == staking_use_cases.POINTER_ADDRESS:
# ensured in _derive_shelley_address:
assert address_parameters.certificate_pointer is not None
await show_warning_tx_pointer_address(
ctx,
address_parameters.certificate_pointer,
@ -657,6 +670,8 @@ async def _show_change_output_staking_warnings(
amount,
)
else:
# ensured in _validate_base_address_staking_info:
assert address_parameters.staking_key_hash
await show_warning_tx_staking_key_hash(
ctx,
address_parameters.staking_key_hash,

@ -8,9 +8,10 @@ from micropython import const
from trezor import log
if False:
from typing import Any, Iterable, List, Tuple
from typing import Any, Iterable, List, Tuple, Union
Value = Any
CborSequence = Union[List[Value], Tuple[Value, ...]]
_CBOR_TYPE_MASK = const(0xE0)
_CBOR_INFO_BITS = const(0x1F)

@ -22,9 +22,6 @@ if False:
from typing_extensions import Protocol
from trezor import wire
# XXX this is a circular import, but it's only for typing
from .keychain import Keychain
Bip32Path = Sequence[int]
Slip21Path = Sequence[bytes]
PathType = TypeVar("PathType", Bip32Path, Slip21Path)
@ -33,6 +30,13 @@ if False:
def match(self, path: Bip32Path) -> bool:
...
class KeychainValidatorType(Protocol):
def is_in_keychain(self, path: Bip32Path) -> bool:
...
def verify_path(self, path: Bip32Path) -> None:
...
class Interval:
"""Helper for testing membership in an interval."""
@ -247,7 +251,10 @@ PATTERN_SEP5 = "m/44'/coin_type'/account'"
async def validate_path(
ctx: wire.Context, keychain: Keychain, path: Bip32Path, *additional_checks: bool
ctx: wire.Context,
keychain: KeychainValidatorType,
path: Bip32Path,
*additional_checks: bool,
) -> None:
keychain.verify_path(path)
if not keychain.is_in_keychain(path) or not all(additional_checks):

@ -419,33 +419,6 @@ class TestCardanoAddress(unittest.TestCase):
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
# block index is None
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=CardanoBlockchainPointerType(block_index=None, tx_index=2, certificate_index=3),
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
# tx index is None
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=CardanoBlockchainPointerType(block_index=1, tx_index=None, certificate_index=3),
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
# certificate index is None
with self.assertRaises(wire.DataError):
address_parameters = CardanoAddressParametersType(
address_type=CardanoAddressType.POINTER,
address_n=[1852 | HARDENED, 1815 | HARDENED, 0 | HARDENED, 0, 0],
certificate_pointer=CardanoBlockchainPointerType(block_index=1, tx_index=2, certificate_index=None),
)
derive_human_readable_address(keychain, address_parameters, 0, 0)
def test_reward_address(self):
mnemonic = "test walk nut penalty hip pave soap entry language right filter choice"
passphrase = ""

Loading…
Cancel
Save