1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

chore(core): decrease tezos size by 860 bytes

This commit is contained in:
grdddj 2022-09-16 18:48:52 +02:00 committed by matejcik
parent 80ab7f1c29
commit 164be3ac8f
6 changed files with 285 additions and 303 deletions

View File

@ -1,16 +1,11 @@
from typing import TYPE_CHECKING
from trezor.crypto import hashlib
from trezor.messages import TezosAddress
from trezor.ui.layouts import show_address
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from . import CURVE, PATTERNS, SLIP44_ID, helpers
from . import CURVE, PATTERNS, SLIP44_ID
if TYPE_CHECKING:
from trezor.messages import TezosGetAddress
from trezor.messages import TezosGetAddress, TezosAddress
from apps.common.keychain import Keychain
from trezor.wire import Context
@ -19,18 +14,22 @@ if TYPE_CHECKING:
async def get_address(
ctx: Context, msg: TezosGetAddress, keychain: Keychain
) -> TezosAddress:
from trezor.crypto import hashlib
from trezor.messages import TezosAddress
from trezor.ui.layouts import show_address
from apps.common import paths, seed
from . import helpers
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pk = seed.remove_ed25519_prefix(node.public_key())
pkh = hashlib.blake2b(pk, outlen=helpers.PUBLIC_KEY_HASH_SIZE).digest()
address = helpers.base58_encode_check(
pkh, prefix=helpers.TEZOS_ED25519_ADDRESS_PREFIX
)
address = helpers.base58_encode_check(pkh, helpers.TEZOS_ED25519_ADDRESS_PREFIX)
if msg.show_display:
title = paths.address_n_to_str(msg.address_n)
await show_address(ctx, address=address, title=title)
await show_address(ctx, address, title=title)
return TezosAddress(address=address)

View File

@ -1,15 +1,11 @@
from typing import TYPE_CHECKING
from trezor.messages import TezosPublicKey
from trezor.ui.layouts import show_pubkey
from apps.common import paths, seed
from apps.common.keychain import with_slip44_keychain
from . import CURVE, PATTERNS, SLIP44_ID, helpers
from . import CURVE, PATTERNS, SLIP44_ID
if TYPE_CHECKING:
from trezor.messages import TezosGetPublicKey
from trezor.messages import TezosGetPublicKey, TezosPublicKey
from apps.common.keychain import Keychain
from trezor.wire import Context
@ -18,11 +14,16 @@ if TYPE_CHECKING:
async def get_public_key(
ctx: Context, msg: TezosGetPublicKey, keychain: Keychain
) -> TezosPublicKey:
from trezor.messages import TezosPublicKey
from trezor.ui.layouts import show_pubkey
from apps.common import paths, seed
from . import helpers
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
pk = seed.remove_ed25519_prefix(node.public_key())
pk_prefixed = helpers.base58_encode_check(pk, prefix=helpers.TEZOS_PUBLICKEY_PREFIX)
pk_prefixed = helpers.base58_encode_check(pk, helpers.TEZOS_PUBLICKEY_PREFIX)
if msg.show_display:
await show_pubkey(ctx, pk_prefixed)

View File

@ -1,12 +1,10 @@
from micropython import const
from typing import TYPE_CHECKING
from trezor import wire
from trezor.crypto import base58
from trezor.utils import BufferReader, ensure
from trezor.wire import DataError
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
@ -83,6 +81,8 @@ _EP_TAG_NAMED = const(255)
def base58_encode_check(payload: bytes, prefix: str | None = None) -> str:
from trezor.crypto import base58
result = payload
if prefix is not None:
result = TEZOS_PREFIX_BYTES[prefix] + payload
@ -90,13 +90,14 @@ def base58_encode_check(payload: bytes, prefix: str | None = None) -> str:
def write_bool(w: Writer, boolean: bool) -> None:
if boolean:
write_uint8(w, 255)
else:
write_uint8(w, 0)
from apps.common.writers import write_uint8
write_uint8(w, 255 if boolean else 0)
def write_instruction(w: Writer, instruction: str) -> None:
from apps.common.writers import write_bytes_unchecked
write_bytes_unchecked(w, MICHELSON_INSTRUCTION_BYTES[instruction])
@ -108,7 +109,7 @@ def check_script_size(script: bytes) -> None:
n = read_uint32_be(r)
ensure(r.remaining_count() == n)
except (AssertionError, EOFError):
raise wire.DataError("Invalid script")
raise DataError("Invalid script")
def check_tx_params_size(params: bytes) -> None:
@ -119,8 +120,8 @@ def check_tx_params_size(params: bytes) -> None:
n = r.get()
r.read(n)
elif tag > 4:
raise wire.DataError("Unknown entrypoint tag")
raise DataError("Unknown entrypoint tag")
n = read_uint32_be(r)
ensure(r.remaining_count() == n)
except (AssertionError, EOFError):
raise wire.DataError("Invalid transaction parameters")
raise DataError("Invalid transaction parameters")

View File

@ -2,39 +2,38 @@ from typing import TYPE_CHECKING
from trezor import ui
from trezor.enums import ButtonRequestType
from trezor.strings import format_amount
from trezor.ui.layouts import (
confirm_address,
confirm_metadata,
confirm_output,
confirm_properties,
confirm_total,
)
from .helpers import TEZOS_AMOUNT_DECIMALS
from trezor.ui.layouts import confirm_address, confirm_metadata, confirm_properties
if TYPE_CHECKING:
from trezor.wire import Context
BR_SIGN_TX = ButtonRequestType.SignTx # global_import_cache
BLUE = ui.BLUE # global_import_cache
async def require_confirm_tx(ctx: Context, to: str, value: int) -> None:
from trezor.ui.layouts import confirm_output
await confirm_output(
ctx,
to,
format_tezos_amount(value),
font_amount=ui.BOLD,
ui.BOLD,
to_str="\nto\n",
width=18,
br_code=ButtonRequestType.SignTx,
br_code=BR_SIGN_TX,
)
async def require_confirm_fee(ctx: Context, value: int, fee: int) -> None:
from trezor.ui.layouts import confirm_total
await confirm_total(
ctx,
total_amount=format_tezos_amount(value),
format_tezos_amount(value),
format_tezos_amount(fee),
total_label="Amount:\n",
fee_amount=format_tezos_amount(fee),
fee_label="\nFee:\n",
)
@ -42,25 +41,25 @@ async def require_confirm_fee(ctx: Context, value: int, fee: int) -> None:
async def require_confirm_origination(ctx: Context, address: str) -> None:
await confirm_address(
ctx,
title="Confirm origination",
address=address,
description="Address:",
br_type="confirm_origination",
"Confirm origination",
address,
"Address:",
"confirm_origination",
BR_SIGN_TX,
icon_color=ui.ORANGE,
br_code=ButtonRequestType.SignTx,
)
async def require_confirm_origination_fee(ctx: Context, balance: int, fee: int) -> None:
await confirm_properties(
ctx,
title="Confirm origination",
props=(
"confirm_origination_final",
"Confirm origination",
(
("Balance:", format_tezos_amount(balance)),
("Fee:", format_tezos_amount(fee)),
),
icon_color=ui.ORANGE,
br_type="confirm_origination_final",
hold=True,
)
@ -68,12 +67,12 @@ async def require_confirm_origination_fee(ctx: Context, balance: int, fee: int)
async def require_confirm_delegation_baker(ctx: Context, baker: str) -> None:
await confirm_address(
ctx,
title="Confirm delegation",
address=baker,
description="Baker address:",
br_type="confirm_delegation",
icon_color=ui.BLUE,
br_code=ButtonRequestType.SignTx,
"Confirm delegation",
baker,
"Baker address:",
"confirm_delegation",
BR_SIGN_TX,
icon_color=BLUE,
)
@ -81,13 +80,13 @@ async def require_confirm_set_delegate(ctx: Context, fee: int) -> None:
await confirm_metadata(
ctx,
"confirm_delegation_final",
title="Confirm delegation",
content="Fee:\n{}",
param=format_tezos_amount(fee),
hold=True,
"Confirm delegation",
"Fee:\n{}",
format_tezos_amount(fee),
BR_SIGN_TX,
hide_continue=True,
icon_color=ui.BLUE,
br_code=ButtonRequestType.SignTx,
hold=True,
icon_color=BLUE,
)
@ -97,17 +96,20 @@ async def require_confirm_register_delegate(
await confirm_properties(
ctx,
"confirm_register_delegate",
title="Register delegate",
props=(
"Register delegate",
(
("Fee:", format_tezos_amount(fee)),
("Address:", address),
),
icon_color=ui.BLUE,
br_code=ButtonRequestType.SignTx,
icon_color=BLUE,
br_code=BR_SIGN_TX,
)
def format_tezos_amount(value: int) -> str:
from trezor.strings import format_amount
from .helpers import TEZOS_AMOUNT_DECIMALS
formatted_value = format_amount(value, TEZOS_AMOUNT_DECIMALS)
return formatted_value + " XTZ"
@ -116,31 +118,24 @@ async def require_confirm_ballot(ctx: Context, proposal: str, ballot: str) -> No
await confirm_properties(
ctx,
"confirm_ballot",
title="Submit ballot",
props=(
"Submit ballot",
(
("Ballot:", ballot),
("Proposal:", proposal),
),
icon_color=ui.PURPLE,
br_code=ButtonRequestType.SignTx,
br_code=BR_SIGN_TX,
)
async def require_confirm_proposals(ctx: Context, proposals: list[str]) -> None:
if len(proposals) > 1:
title = "Submit proposals"
else:
title = "Submit proposal"
await confirm_properties(
ctx,
"confirm_proposals",
title=title,
props=[
("Proposal " + str(i), proposal) for i, proposal in enumerate(proposals, 1)
],
"Submit proposals" if len(proposals) > 1 else "Submit proposal",
[("Proposal " + str(i), proposal) for i, proposal in enumerate(proposals, 1)],
icon_color=ui.PURPLE,
br_code=ButtonRequestType.SignTx,
br_code=BR_SIGN_TX,
)
@ -149,13 +144,13 @@ async def require_confirm_delegation_manager_withdraw(
) -> None:
await confirm_address(
ctx,
title="Remove delegation",
address=address,
description="Delegator:",
br_type="confirm_undelegation",
"Remove delegation",
address,
"Delegator:",
"confirm_undelegation",
BR_SIGN_TX,
icon=ui.ICON_RECEIVE,
icon_color=ui.RED,
br_code=ButtonRequestType.SignTx,
)
@ -163,12 +158,12 @@ async def require_confirm_manager_remove_delegate(ctx: Context, fee: int) -> Non
await confirm_metadata(
ctx,
"confirm_undelegation_final",
title="Remove delegation",
content="Fee:\n{}",
param=format_tezos_amount(fee),
hold=True,
"Remove delegation",
"Fee:\n{}",
format_tezos_amount(fee),
BR_SIGN_TX,
hide_continue=True,
hold=True,
icon=ui.ICON_RECEIVE,
icon_color=ui.RED,
br_code=ButtonRequestType.SignTx,
)

View File

@ -1,21 +1,19 @@
from typing import TYPE_CHECKING
from trezor import wire
from trezor.crypto import hashlib
from trezor.crypto.curve import ed25519
from trezor.enums import TezosBallotType, TezosContractType
from trezor.messages import TezosSignedTx
from trezor.enums import TezosContractType
from trezor.wire import DataError
from apps.common import paths
from apps.common.keychain import with_slip44_keychain
from apps.common.writers import (
write_bytes_fixed,
write_bytes_unchecked,
write_uint8,
write_uint32_be,
)
from apps.common.writers import write_bytes_fixed, write_uint8, write_uint32_be
from . import CURVE, PATTERNS, SLIP44_ID, helpers, layout
from . import CURVE, PATTERNS, SLIP44_ID, helpers
from .helpers import ( # symbols used more than once
CONTRACT_ID_SIZE,
TAGGED_PUBKEY_HASH_SIZE,
base58_encode_check,
write_bool,
write_instruction,
)
if TYPE_CHECKING:
from apps.common.keychain import Keychain
@ -23,99 +21,115 @@ if TYPE_CHECKING:
from trezor.messages import (
TezosSignTx,
TezosContractID,
TezosManagerTransfer,
TezosBallotOp,
TezosProposalOp,
TezosRevealOp,
TezosDelegationOp,
TezosTransactionOp,
TezosOriginationOp,
TezosSignedTx,
)
from trezor.utils import Writer
@with_slip44_keychain(*PATTERNS, slip44_id=SLIP44_ID, curve=CURVE)
async def sign_tx(ctx: Context, msg: TezosSignTx, keychain: Keychain) -> TezosSignedTx:
await paths.validate_path(ctx, keychain, msg.address_n)
from trezor.crypto import hashlib
from trezor.crypto.curve import ed25519
from apps.common.paths import validate_path
from trezor.messages import TezosSignedTx
from trezor.enums import TezosBallotType
from . import layout
await validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
transaction = msg.transaction # local_cache_attribute
origination = msg.origination # local_cache_attribute
delegation = msg.delegation # local_cache_attribute
if transaction is not None:
fee = transaction.fee # local_cache_attribute
parameters_manager = transaction.parameters_manager # local_cache_attribute
if msg.transaction is not None:
# if the transaction operation is used to execute code on a smart contract
if msg.transaction.parameters_manager is not None:
parameters_manager = msg.transaction.parameters_manager
if parameters_manager is not None:
transfer = parameters_manager.transfer # local_cache_attribute
# operation to delegate from a smart contract with manager.tz
if parameters_manager.set_delegate is not None:
delegate = _get_address_by_tag(parameters_manager.set_delegate)
await layout.require_confirm_delegation_baker(ctx, delegate)
await layout.require_confirm_set_delegate(ctx, msg.transaction.fee)
await layout.require_confirm_set_delegate(ctx, fee)
# operation to remove delegate from the smart contract with manager.tz
elif parameters_manager.cancel_delegate is not None:
address = _get_address_from_contract(msg.transaction.destination)
address = _get_address_from_contract(transaction.destination)
await layout.require_confirm_delegation_manager_withdraw(ctx, address)
await layout.require_confirm_manager_remove_delegate(
ctx, msg.transaction.fee
)
await layout.require_confirm_manager_remove_delegate(ctx, fee)
# operation to transfer tokens from a smart contract to an implicit account or a smart contract
elif parameters_manager.transfer is not None:
to = _get_address_from_contract(parameters_manager.transfer.destination)
await layout.require_confirm_tx(
ctx, to, parameters_manager.transfer.amount
)
await layout.require_confirm_fee(
ctx, parameters_manager.transfer.amount, msg.transaction.fee
)
elif transfer is not None:
to = _get_address_from_contract(transfer.destination)
await layout.require_confirm_tx(ctx, to, transfer.amount)
await layout.require_confirm_fee(ctx, transfer.amount, fee)
else:
# transactions from an implicit account
to = _get_address_from_contract(msg.transaction.destination)
await layout.require_confirm_tx(ctx, to, msg.transaction.amount)
await layout.require_confirm_fee(
ctx, msg.transaction.amount, msg.transaction.fee
)
to = _get_address_from_contract(transaction.destination)
await layout.require_confirm_tx(ctx, to, transaction.amount)
await layout.require_confirm_fee(ctx, transaction.amount, fee)
elif msg.origination is not None:
source = _get_address_by_tag(msg.origination.source)
elif origination is not None:
source = _get_address_by_tag(origination.source)
await layout.require_confirm_origination(ctx, source)
# if we are immediately delegating contract
if msg.origination.delegate is not None:
delegate = _get_address_by_tag(msg.origination.delegate)
if origination.delegate is not None:
delegate = _get_address_by_tag(origination.delegate)
await layout.require_confirm_delegation_baker(ctx, delegate)
await layout.require_confirm_origination_fee(
ctx, msg.origination.balance, msg.origination.fee
ctx, origination.balance, origination.fee
)
elif msg.delegation is not None:
source = _get_address_by_tag(msg.delegation.source)
elif delegation is not None:
source = _get_address_by_tag(delegation.source)
delegate_address: str | None = None
if msg.delegation.delegate is not None:
delegate_address = _get_address_by_tag(msg.delegation.delegate)
if delegation.delegate is not None:
delegate_address = _get_address_by_tag(delegation.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)
await layout.require_confirm_set_delegate(ctx, delegation.fee)
# if account registers itself as a delegate
else:
await layout.require_confirm_register_delegate(
ctx, source, msg.delegation.fee
)
await layout.require_confirm_register_delegate(ctx, source, delegation.fee)
elif msg.proposal is not None:
proposed_protocols = [_get_protocol_hash(p) for p in msg.proposal.proposals]
proposed_protocols = [
# _get_protocol_hash
base58_encode_check(p, "P")
for p in msg.proposal.proposals
]
await layout.require_confirm_proposals(ctx, proposed_protocols)
elif msg.ballot is not None:
proposed_protocol = _get_protocol_hash(msg.ballot.proposal)
submitted_ballot = _get_ballot(msg.ballot.ballot)
# _get_protocol_hash
proposed_protocol = base58_encode_check(msg.ballot.proposal, "P")
# _get_ballot
if msg.ballot.ballot == TezosBallotType.Yay:
submitted_ballot = "yay"
elif msg.ballot.ballot == TezosBallotType.Nay:
submitted_ballot = "nay"
elif msg.ballot.ballot == TezosBallotType.Pass:
submitted_ballot = "pass"
else:
raise RuntimeError # unrecognized enum value
await layout.require_confirm_ballot(ctx, proposed_protocol, submitted_ballot)
else:
raise wire.DataError("Invalid operation")
raise DataError("Invalid operation")
w = bytearray()
_get_operation_bytes(w, msg)
@ -131,11 +145,9 @@ async def sign_tx(ctx: Context, msg: TezosSignTx, keychain: Keychain) -> TezosSi
sig_op_contents = opbytes + signature
sig_op_contents_hash = hashlib.blake2b(sig_op_contents, outlen=32).digest()
ophash = helpers.base58_encode_check(sig_op_contents_hash, prefix="o")
ophash = base58_encode_check(sig_op_contents_hash, "o")
sig_prefixed = helpers.base58_encode_check(
signature, prefix=helpers.TEZOS_SIGNATURE_PREFIX
)
sig_prefixed = base58_encode_check(signature, helpers.TEZOS_SIGNATURE_PREFIX)
return TezosSignedTx(
signature=sig_prefixed, sig_op_contents=sig_op_contents, operation_hash=ophash
@ -147,8 +159,8 @@ def _get_address_by_tag(address_hash: bytes) -> str:
tag = int(address_hash[0])
if 0 <= tag < len(prefixes):
return helpers.base58_encode_check(address_hash[1:], prefix=prefixes[tag])
raise wire.DataError("Invalid tag in address hash")
return base58_encode_check(address_hash[1:], prefixes[tag])
raise DataError("Invalid tag in address hash")
def _get_address_from_contract(address: TezosContractID) -> str:
@ -156,94 +168,144 @@ def _get_address_from_contract(address: TezosContractID) -> str:
return _get_address_by_tag(address.hash)
elif address.tag == TezosContractType.Originated:
return helpers.base58_encode_check(
address.hash[:-1], prefix=helpers.TEZOS_ORIGINATED_ADDRESS_PREFIX
return base58_encode_check(
address.hash[:-1], helpers.TEZOS_ORIGINATED_ADDRESS_PREFIX
)
raise wire.DataError("Invalid contract type")
def _get_protocol_hash(proposal: bytes) -> str:
return helpers.base58_encode_check(proposal, prefix="P")
def _get_ballot(ballot: TezosBallotType) -> str:
if ballot == TezosBallotType.Yay:
return "yay"
elif ballot == TezosBallotType.Nay:
return "nay"
elif ballot == TezosBallotType.Pass:
return "pass"
raise RuntimeError # unrecognized enum value
raise DataError("Invalid contract type")
def _get_operation_bytes(w: Writer, msg: TezosSignTx) -> None:
from apps.common.writers import write_bytes_unchecked
from .helpers import PROPOSAL_HASH_SIZE
reveal = msg.reveal # local_cache_attribute
write_bytes_fixed(w, msg.branch, helpers.BRANCH_HASH_SIZE)
# when the account sends first operation in lifetime,
# we need to reveal its public key
if msg.reveal is not None:
_encode_common(w, msg.reveal, "reveal")
tag = int(msg.reveal.public_key[0])
if reveal is not None:
_encode_common(w, reveal, "reveal")
tag = int(reveal.public_key[0])
try:
public_key_size = helpers.PUBLIC_KEY_TAG_TO_SIZE[tag]
except KeyError:
raise wire.DataError("Invalid tag in public key")
raise DataError("Invalid tag in public key")
write_bytes_fixed(w, msg.reveal.public_key, 1 + public_key_size)
write_bytes_fixed(w, reveal.public_key, 1 + public_key_size)
# transaction operation
if msg.transaction is not None:
_encode_common(w, msg.transaction, "transaction")
_encode_zarith(w, msg.transaction.amount)
_encode_contract_id(w, msg.transaction.destination)
transaction = msg.transaction
_encode_common(w, transaction, "transaction")
_encode_zarith(w, transaction.amount)
# _encode_contract_id
contract_id = transaction.destination
write_uint8(w, contract_id.tag)
write_bytes_fixed(w, contract_id.hash, CONTRACT_ID_SIZE - 1)
# support delegation and transfer from the old scriptless contracts (now with manager.tz script)
if msg.transaction.parameters_manager is not None:
parameters_manager = msg.transaction.parameters_manager
if transaction.parameters_manager is not None:
parameters_manager = transaction.parameters_manager # local_cache_attribute
transfer = parameters_manager.transfer # local_cache_attribute
if parameters_manager.set_delegate is not None:
_encode_manager_delegation(w, parameters_manager.set_delegate)
# _encode_manager_delegation
delegate = parameters_manager.set_delegate
michelson_length = 42
_encode_manager_common(w, michelson_length, "PUSH")
write_bytes_fixed(w, delegate, TAGGED_PUBKEY_HASH_SIZE)
for i in ("SOME", "SET_DELEGATE", "CONS"):
write_instruction(w, i)
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
):
_encode_manager_to_implicit_transfer(w, parameters_manager.transfer)
# _encode_manager_delegation_remove
michelson_length = 14
_encode_manager_common(w, michelson_length, "NONE")
for i in ("SET_DELEGATE", "CONS"):
write_instruction(w, i)
elif transfer is not None:
assert transfer.destination is not None
if transfer.destination.tag == TezosContractType.Implicit:
# _encode_manager_to_implicit_transfer
manager_transfer = transfer
michelson_length = 48
value_natural = bytearray()
_encode_natural(value_natural, manager_transfer.amount)
sequence_length = michelson_length + len(value_natural)
_encode_manager_common(w, sequence_length, "PUSH")
write_bytes_fixed(
w, manager_transfer.destination.hash, TAGGED_PUBKEY_HASH_SIZE
)
for i in ("IMPLICIT_ACCOUNT", "PUSH", "mutez"):
write_instruction(w, i)
_encode_natural(w, manager_transfer.amount)
for i in ("UNIT", "TRANSFER_TOKENS", "CONS"):
write_instruction(w, i)
else:
_encode_manager_to_manager_transfer(w, parameters_manager.transfer)
# _encode_manager_to_manager_transfer
manager_transfer = transfer
michelson_length = 77
value_natural = bytearray()
_encode_natural(value_natural, manager_transfer.amount)
sequence_length = michelson_length + len(value_natural)
_encode_manager_common(w, sequence_length, "PUSH", to_contract=True)
# _encode_contract_id
contract_id = manager_transfer.destination
write_uint8(w, contract_id.tag)
write_bytes_fixed(w, contract_id.hash, CONTRACT_ID_SIZE - 1)
for i in ("CONTRACT", "unit", "ASSERT_SOME", "PUSH", "mutez"):
write_instruction(w, i)
_encode_natural(w, manager_transfer.amount)
for i in ("UNIT", "TRANSFER_TOKENS", "CONS"):
write_instruction(w, i)
else:
if msg.transaction.parameters:
helpers.write_bool(w, True)
helpers.check_tx_params_size(msg.transaction.parameters)
write_bytes_unchecked(w, msg.transaction.parameters)
parameters = transaction.parameters # local_cache_attribute
if parameters:
write_bool(w, True)
helpers.check_tx_params_size(parameters)
write_bytes_unchecked(w, parameters)
else:
helpers.write_bool(w, False)
write_bool(w, False)
# origination operation
elif msg.origination is not None:
_encode_common(w, msg.origination, "origination")
_encode_zarith(w, msg.origination.balance)
_encode_data_with_bool_prefix(
w, msg.origination.delegate, helpers.TAGGED_PUBKEY_HASH_SIZE
)
helpers.check_script_size(msg.origination.script)
write_bytes_unchecked(w, msg.origination.script)
origination = msg.origination
_encode_common(w, origination, "origination")
_encode_zarith(w, origination.balance)
_encode_data_with_bool_prefix(w, origination.delegate, TAGGED_PUBKEY_HASH_SIZE)
helpers.check_script_size(origination.script)
write_bytes_unchecked(w, origination.script)
# delegation operation
elif msg.delegation is not None:
_encode_common(w, msg.delegation, "delegation")
_encode_data_with_bool_prefix(
w, msg.delegation.delegate, helpers.TAGGED_PUBKEY_HASH_SIZE
w, msg.delegation.delegate, TAGGED_PUBKEY_HASH_SIZE
)
elif msg.proposal is not None:
_encode_proposal(w, msg.proposal)
# _encode_proposal
proposal = msg.proposal
write_uint8(w, helpers.OP_TAG_PROPOSALS)
write_bytes_fixed(w, proposal.source, TAGGED_PUBKEY_HASH_SIZE)
write_uint32_be(w, proposal.period)
write_uint32_be(w, len(proposal.proposals) * PROPOSAL_HASH_SIZE)
for proposal_hash in proposal.proposals:
write_bytes_fixed(w, proposal_hash, PROPOSAL_HASH_SIZE)
elif msg.ballot is not None:
_encode_ballot(w, msg.ballot)
# _encode_ballot
ballot = msg.ballot
write_uint8(w, helpers.OP_TAG_BALLOT)
write_bytes_fixed(w, ballot.source, TAGGED_PUBKEY_HASH_SIZE)
write_uint32_be(w, ballot.period)
write_bytes_fixed(w, ballot.proposal, PROPOSAL_HASH_SIZE)
write_uint8(w, ballot.ballot)
def _encode_common(
@ -261,16 +323,14 @@ def _encode_common(
"delegation": helpers.OP_TAG_DELEGATION,
}
write_uint8(w, operation_tags[str_operation])
write_bytes_fixed(w, operation.source, helpers.TAGGED_PUBKEY_HASH_SIZE)
_encode_zarith(w, operation.fee)
_encode_zarith(w, operation.counter)
_encode_zarith(w, operation.gas_limit)
_encode_zarith(w, operation.storage_limit)
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)
write_bytes_fixed(w, operation.source, TAGGED_PUBKEY_HASH_SIZE)
for num in (
operation.fee,
operation.counter,
operation.gas_limit,
operation.storage_limit,
):
_encode_zarith(w, num)
def _encode_data_with_bool_prefix(
@ -295,23 +355,6 @@ def _encode_zarith(w: Writer, num: int) -> None:
write_uint8(w, 128 | byte)
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)
write_uint32_be(w, len(proposal.proposals) * helpers.PROPOSAL_HASH_SIZE)
for proposal_hash in proposal.proposals:
write_bytes_fixed(w, proposal_hash, helpers.PROPOSAL_HASH_SIZE)
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)
write_bytes_fixed(w, ballot.proposal, helpers.PROPOSAL_HASH_SIZE)
write_uint8(w, ballot.ballot)
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
@ -334,84 +377,20 @@ def _encode_manager_common(
# 5 = tag and sequence_length (1 byte + 4 bytes)
argument_length = sequence_length + 5
helpers.write_bool(w, True)
write_bool(w, True)
write_uint8(w, helpers.DO_ENTRYPOINT_TAG)
write_uint32_be(w, argument_length)
write_uint8(w, helpers.MICHELSON_SEQUENCE_TAG)
write_uint32_be(w, sequence_length)
helpers.write_instruction(w, "DROP")
helpers.write_instruction(w, "NIL")
helpers.write_instruction(w, "operation")
helpers.write_instruction(w, operation)
for i in ("DROP", "NIL", "operation", operation):
write_instruction(w, i)
if to_contract:
helpers.write_instruction(w, "address")
write_instruction(w, "address")
else:
helpers.write_instruction(w, "key_hash")
write_instruction(w, "key_hash")
if operation == "PUSH":
write_uint8(w, 10) # byte sequence
if to_contract:
write_uint32_be(w, helpers.CONTRACT_ID_SIZE)
write_uint32_be(w, CONTRACT_ID_SIZE)
else:
write_uint32_be(w, helpers.TAGGED_PUBKEY_HASH_SIZE)
def _encode_manager_to_implicit_transfer(
w: Writer, manager_transfer: TezosManagerTransfer
) -> None:
MICHELSON_LENGTH = 48
value_natural = bytearray()
_encode_natural(value_natural, manager_transfer.amount)
sequence_length = MICHELSON_LENGTH + len(value_natural)
_encode_manager_common(w, sequence_length, "PUSH")
write_bytes_fixed(
w, manager_transfer.destination.hash, helpers.TAGGED_PUBKEY_HASH_SIZE
)
helpers.write_instruction(w, "IMPLICIT_ACCOUNT")
helpers.write_instruction(w, "PUSH")
helpers.write_instruction(w, "mutez")
_encode_natural(w, manager_transfer.amount)
helpers.write_instruction(w, "UNIT")
helpers.write_instruction(w, "TRANSFER_TOKENS")
helpers.write_instruction(w, "CONS")
# smart_contract_delegation
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")
write_bytes_fixed(w, delegate, helpers.TAGGED_PUBKEY_HASH_SIZE)
helpers.write_instruction(w, "SOME")
helpers.write_instruction(w, "SET_DELEGATE")
helpers.write_instruction(w, "CONS")
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: Writer, manager_transfer: TezosManagerTransfer
) -> None:
MICHELSON_LENGTH = 77
value_natural = bytearray()
_encode_natural(value_natural, manager_transfer.amount)
sequence_length = MICHELSON_LENGTH + len(value_natural)
_encode_manager_common(w, sequence_length, "PUSH", to_contract=True)
_encode_contract_id(w, manager_transfer.destination)
helpers.write_instruction(w, "CONTRACT")
helpers.write_instruction(w, "unit")
helpers.write_instruction(w, "ASSERT_SOME")
helpers.write_instruction(w, "PUSH")
helpers.write_instruction(w, "mutez")
_encode_natural(w, manager_transfer.amount)
helpers.write_instruction(w, "UNIT")
helpers.write_instruction(w, "TRANSFER_TOKENS")
helpers.write_instruction(w, "CONS")
write_uint32_be(w, TAGGED_PUBKEY_HASH_SIZE)

View File

@ -3,15 +3,22 @@ from common import *
if not utils.BITCOIN_ONLY:
from trezor.enums import TezosContractType
from trezor.messages import TezosContractID
from apps.tezos.helpers import base58_encode_check, write_bool
from apps.tezos.helpers import base58_encode_check, write_bool, CONTRACT_ID_SIZE
from apps.tezos.sign_tx import (
_encode_contract_id,
write_uint8,
write_bytes_fixed,
_encode_data_with_bool_prefix,
_encode_zarith,
_encode_natural,
)
# NOTE: copy-pasted from apps.tezos.sign_tx
def _encode_contract_id(w: "Writer", contract_id: TezosContractID) -> None:
write_uint8(w, contract_id.tag)
write_bytes_fixed(w, contract_id.hash, CONTRACT_ID_SIZE - 1)
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
class TestTezosEncoding(unittest.TestCase):
def test_tezos_encode_zarith(self):