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

chore(core): decrease eos size by 1kb

This commit is contained in:
grdddj 2022-09-16 15:59:09 +02:00 committed by matejcik
parent 47b924cbec
commit 80ab7f1c29
9 changed files with 335 additions and 337 deletions

View File

@ -1,119 +1,125 @@
from typing import TYPE_CHECKING
from trezor.crypto.hashlib import sha256
from trezor.messages import EosTxActionAck, EosTxActionRequest
from trezor.utils import HashWriter
from .. import helpers, writers
from . import layout
if TYPE_CHECKING:
from trezor import wire
from trezor.utils import Writer
from trezor.utils import Writer, HashWriter
from trezor.messages import EosTxActionAck
async def process_action(
ctx: wire.Context, sha: HashWriter, action: EosTxActionAck
) -> None:
from .. import helpers, writers
from . import layout
name = helpers.eos_name_to_string(action.common.name)
account = helpers.eos_name_to_string(action.common.account)
if not check_action(action, name, account):
if not _check_action(action, name, account):
raise ValueError("Invalid action")
w = bytearray()
if account == "eosio":
if name == "buyram":
assert action.buy_ram is not None # check_action
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
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
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
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
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
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
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
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
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
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
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
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
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:
await process_unknown_action(ctx, w, action)
await _process_unknown_action(ctx, w, action)
writers.write_action_common(sha, action.common)
writers.write_bytes_prefixed(sha, w)
async def process_unknown_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)
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
from trezor.messages import EosTxActionAck, EosTxActionRequest
from .. import writers
from . import layout
writers.write_bytes_unchecked(w, action.unknown.data_chunk)
bytes_left = action.unknown.data_size - len(action.unknown.data_chunk)
unknown = action.unknown # local_cache_attribute
assert unknown is not None
data_chunk = unknown.data_chunk # local_cache_attribute
checksum = HashWriter(sha256())
writers.write_uvarint(checksum, unknown.data_size)
checksum.extend(data_chunk)
writers.write_bytes_unchecked(w, data_chunk)
bytes_left = unknown.data_size - len(data_chunk)
while bytes_left != 0:
action = await ctx.call(
EosTxActionRequest(data_size=bytes_left), EosTxActionAck
)
if action.unknown is None:
if unknown is None:
raise ValueError("Bad response. Unknown struct expected.")
checksum.extend(action.unknown.data_chunk)
writers.write_bytes_unchecked(w, action.unknown.data_chunk)
checksum.extend(data_chunk)
writers.write_bytes_unchecked(w, data_chunk)
bytes_left -= len(action.unknown.data_chunk)
bytes_left -= len(data_chunk)
if bytes_left < 0:
raise ValueError("Bad response. Buffer overflow.")
await layout.confirm_action_unknown(ctx, action.common, checksum.get_digest())
def check_action(action: EosTxActionAck, name: str, account: str) -> bool:
def _check_action(action: EosTxActionAck, name: str, account: str) -> bool:
if account == "eosio":
return (
(name == "buyram" and action.buy_ram is not None)

View File

@ -1,12 +1,14 @@
from typing import TYPE_CHECKING
from trezor import ui, wire
from trezor import ui
from trezor.enums import ButtonRequestType
from trezor.ui.layouts import confirm_properties
from .. import helpers
from ..helpers import eos_asset_to_string, eos_name_to_string
if TYPE_CHECKING:
from typing import Iterable
from trezor.wire import Context
from trezor.messages import (
EosActionBuyRam,
EosActionBuyRamBytes,
@ -27,313 +29,294 @@ if TYPE_CHECKING:
from trezor.ui.layouts import PropertyType
async def confirm_action_buyram(ctx: wire.Context, msg: EosActionBuyRam) -> None:
# Because icon and br_code are almost always the same
# (and also calling with positional arguments takes less space)
async def _confirm_properties(
ctx: Context,
br_type: str,
title: str,
props: Iterable[PropertyType],
) -> None:
await confirm_properties(
ctx,
br_type,
title,
props,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
)
async def confirm_action_buyram(ctx: Context, msg: EosActionBuyRam) -> None:
await _confirm_properties(
ctx,
"confirm_buyram",
title="Buy RAM",
props=[
("Payer:", helpers.eos_name_to_string(msg.payer)),
("Receiver:", helpers.eos_name_to_string(msg.receiver)),
("Amount:", helpers.eos_asset_to_string(msg.quantity)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Buy RAM",
(
("Payer:", eos_name_to_string(msg.payer)),
("Receiver:", eos_name_to_string(msg.receiver)),
("Amount:", eos_asset_to_string(msg.quantity)),
),
)
async def confirm_action_buyrambytes(
ctx: wire.Context, msg: EosActionBuyRamBytes
) -> None:
await confirm_properties(
async def confirm_action_buyrambytes(ctx: Context, msg: EosActionBuyRamBytes) -> None:
await _confirm_properties(
ctx,
"confirm_buyrambytes",
title="Buy RAM",
props=[
("Payer:", helpers.eos_name_to_string(msg.payer)),
("Receiver:", helpers.eos_name_to_string(msg.receiver)),
"Buy RAM",
(
("Payer:", eos_name_to_string(msg.payer)),
("Receiver:", eos_name_to_string(msg.receiver)),
("Bytes:", str(msg.bytes)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
),
)
async def confirm_action_delegate(ctx: wire.Context, msg: EosActionDelegate) -> None:
async def confirm_action_delegate(ctx: Context, msg: EosActionDelegate) -> None:
props = [
("Sender:", helpers.eos_name_to_string(msg.sender)),
("Receiver:", helpers.eos_name_to_string(msg.receiver)),
("CPU:", helpers.eos_asset_to_string(msg.cpu_quantity)),
("NET:", helpers.eos_asset_to_string(msg.net_quantity)),
("Sender:", eos_name_to_string(msg.sender)),
("Receiver:", eos_name_to_string(msg.receiver)),
("CPU:", eos_asset_to_string(msg.cpu_quantity)),
("NET:", eos_asset_to_string(msg.net_quantity)),
]
append = props.append # local_cache_attribute
if msg.transfer:
props.append(("Transfer:", "Yes"))
props.append(("Receiver:", helpers.eos_name_to_string(msg.receiver)))
append(("Transfer:", "Yes"))
append(("Receiver:", eos_name_to_string(msg.receiver)))
else:
props.append(("Transfer:", "No"))
append(("Transfer:", "No"))
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_delegate",
title="Delegate",
props=props,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Delegate",
props,
)
async def confirm_action_sellram(ctx: wire.Context, msg: EosActionSellRam) -> None:
await confirm_properties(
async def confirm_action_sellram(ctx: Context, msg: EosActionSellRam) -> None:
await _confirm_properties(
ctx,
"confirm_sellram",
title="Sell RAM",
props=[
("Receiver:", helpers.eos_name_to_string(msg.account)),
"Sell RAM",
(
("Receiver:", eos_name_to_string(msg.account)),
("Bytes:", str(msg.bytes)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
),
)
async def confirm_action_undelegate(
ctx: wire.Context, msg: EosActionUndelegate
) -> None:
await confirm_properties(
async def confirm_action_undelegate(ctx: Context, msg: EosActionUndelegate) -> None:
await _confirm_properties(
ctx,
"confirm_undelegate",
title="Undelegate",
props=[
("Sender:", helpers.eos_name_to_string(msg.sender)),
("Receiver:", helpers.eos_name_to_string(msg.receiver)),
("CPU:", helpers.eos_asset_to_string(msg.cpu_quantity)),
("NET:", helpers.eos_asset_to_string(msg.net_quantity)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Undelegate",
(
("Sender:", eos_name_to_string(msg.sender)),
("Receiver:", eos_name_to_string(msg.receiver)),
("CPU:", eos_asset_to_string(msg.cpu_quantity)),
("NET:", eos_asset_to_string(msg.net_quantity)),
),
)
async def confirm_action_refund(ctx: wire.Context, msg: EosActionRefund) -> None:
await confirm_properties(
async def confirm_action_refund(ctx: Context, msg: EosActionRefund) -> None:
await _confirm_properties(
ctx,
"confirm_refund",
title="Refund",
props=[
("Owner:", helpers.eos_name_to_string(msg.owner)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Refund",
(("Owner:", eos_name_to_string(msg.owner)),),
)
async def confirm_action_voteproducer(
ctx: wire.Context, msg: EosActionVoteProducer
) -> None:
if msg.proxy and not msg.producers:
async def confirm_action_voteproducer(ctx: Context, msg: EosActionVoteProducer) -> None:
producers = msg.producers # local_cache_attribute
if msg.proxy and not producers:
# PROXY
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_voteproducer",
title="Vote for proxy",
props=[
("Voter:", helpers.eos_name_to_string(msg.voter)),
("Proxy:", helpers.eos_name_to_string(msg.proxy)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Vote for proxy",
(
("Voter:", eos_name_to_string(msg.voter)),
("Proxy:", eos_name_to_string(msg.proxy)),
),
)
elif msg.producers:
elif producers:
# PRODUCERS
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_voteproducer",
title="Vote for producers",
props=(
(f"{wi:2d}. {helpers.eos_name_to_string(producer)}", None)
for wi, producer in enumerate(msg.producers, 1)
"Vote for producers",
(
(f"{wi:2d}. {eos_name_to_string(producer)}", None)
for wi, producer in enumerate(producers, 1)
),
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
)
else:
# Cancel vote
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_voteproducer",
title="Cancel vote",
props=[
("Voter:", helpers.eos_name_to_string(msg.voter)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Cancel vote",
(("Voter:", eos_name_to_string(msg.voter)),),
)
async def confirm_action_transfer(
ctx: wire.Context, msg: EosActionTransfer, account: str
ctx: Context, msg: EosActionTransfer, account: str
) -> None:
props = [
("From:", helpers.eos_name_to_string(msg.sender)),
("To:", helpers.eos_name_to_string(msg.receiver)),
("Amount:", helpers.eos_asset_to_string(msg.quantity)),
("From:", eos_name_to_string(msg.sender)),
("To:", eos_name_to_string(msg.receiver)),
("Amount:", eos_asset_to_string(msg.quantity)),
("Contract:", account),
]
if msg.memo is not None:
props.append(("Memo", msg.memo[:512]))
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_transfer",
title="Transfer",
props=props,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Transfer",
props,
)
async def confirm_action_updateauth(
ctx: wire.Context, msg: EosActionUpdateAuth
) -> None:
async def confirm_action_updateauth(ctx: Context, msg: EosActionUpdateAuth) -> None:
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)),
("Account:", eos_name_to_string(msg.account)),
("Permission:", eos_name_to_string(msg.permission)),
("Parent:", eos_name_to_string(msg.parent)),
]
props.extend(authorization_fields(msg.auth))
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_updateauth",
title="Update Auth",
props=props,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Update Auth",
props,
)
async def confirm_action_deleteauth(
ctx: wire.Context, msg: EosActionDeleteAuth
) -> None:
await confirm_properties(
async def confirm_action_deleteauth(ctx: Context, msg: EosActionDeleteAuth) -> None:
await _confirm_properties(
ctx,
"confirm_deleteauth",
title="Delete Auth",
props=[
("Account:", helpers.eos_name_to_string(msg.account)),
("Permission:", helpers.eos_name_to_string(msg.permission)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Delete Auth",
(
("Account:", eos_name_to_string(msg.account)),
("Permission:", eos_name_to_string(msg.permission)),
),
)
async def confirm_action_linkauth(ctx: wire.Context, msg: EosActionLinkAuth) -> None:
await confirm_properties(
async def confirm_action_linkauth(ctx: Context, msg: EosActionLinkAuth) -> None:
await _confirm_properties(
ctx,
"confirm_linkauth",
title="Link Auth",
props=[
("Account:", helpers.eos_name_to_string(msg.account)),
("Code:", helpers.eos_name_to_string(msg.code)),
("Type:", helpers.eos_name_to_string(msg.type)),
("Requirement:", helpers.eos_name_to_string(msg.requirement)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Link Auth",
(
("Account:", eos_name_to_string(msg.account)),
("Code:", eos_name_to_string(msg.code)),
("Type:", eos_name_to_string(msg.type)),
("Requirement:", eos_name_to_string(msg.requirement)),
),
)
async def confirm_action_unlinkauth(
ctx: wire.Context, msg: EosActionUnlinkAuth
) -> None:
await confirm_properties(
async def confirm_action_unlinkauth(ctx: Context, msg: EosActionUnlinkAuth) -> None:
await _confirm_properties(
ctx,
"confirm_unlinkauth",
title="Unlink Auth",
props=[
("Account:", helpers.eos_name_to_string(msg.account)),
("Code:", helpers.eos_name_to_string(msg.code)),
("Type:", helpers.eos_name_to_string(msg.type)),
],
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"Unlink Auth",
(
("Account:", eos_name_to_string(msg.account)),
("Code:", eos_name_to_string(msg.code)),
("Type:", eos_name_to_string(msg.type)),
),
)
async def confirm_action_newaccount(
ctx: wire.Context, msg: EosActionNewAccount
) -> None:
async def confirm_action_newaccount(ctx: Context, msg: EosActionNewAccount) -> None:
props: list[PropertyType] = [
("Creator:", helpers.eos_name_to_string(msg.creator)),
("Name:", helpers.eos_name_to_string(msg.name)),
("Creator:", eos_name_to_string(msg.creator)),
("Name:", eos_name_to_string(msg.name)),
]
props.extend(authorization_fields(msg.owner))
props.extend(authorization_fields(msg.active))
await confirm_properties(
await _confirm_properties(
ctx,
"confirm_newaccount",
title="New Account",
props=props,
icon=ui.ICON_CONFIRM,
br_code=ButtonRequestType.ConfirmOutput,
"New Account",
props,
)
async def confirm_action_unknown(
ctx: wire.Context, action: EosActionCommon, checksum: bytes
ctx: Context, action: EosActionCommon, checksum: bytes
) -> None:
await confirm_properties(
ctx,
"confirm_unknown",
title="Arbitrary data",
props=[
("Contract:", helpers.eos_name_to_string(action.account)),
("Action Name:", helpers.eos_name_to_string(action.name)),
"Arbitrary data",
(
("Contract:", eos_name_to_string(action.account)),
("Action Name:", eos_name_to_string(action.name)),
("Checksum:", checksum),
],
icon=ui.ICON_WIPE,
icon_color=ui.RED,
),
ui.ICON_WIPE,
ui.RED,
br_code=ButtonRequestType.ConfirmOutput,
)
def authorization_fields(auth: EosAuthorization) -> list[PropertyType]:
from trezor.wire import DataError
from ..helpers import public_key_to_wif
fields: list[PropertyType] = []
fields.append(("Threshold:", str(auth.threshold)))
append = fields.append # local_cache_attribute
append(("Threshold:", str(auth.threshold)))
# NOTE: getting rid of f-strings saved almost 100 bytes
for i, key in enumerate(auth.keys, 1):
if key.key is None:
raise wire.DataError("Key must be provided explicitly.")
raise DataError("Key must be provided explicitly.")
_key = helpers.public_key_to_wif(bytes(key.key))
_key = public_key_to_wif(bytes(key.key))
_weight = str(key.weight)
header = f"Key #{i}:"
w_header = f"Key #{i} Weight:"
header = "Key #" + str(i) + ":"
w_header = "Key #" + str(i) + " Weight:"
fields.append((header, _key))
fields.append((w_header, _weight))
append((header, _key))
append((w_header, _weight))
for i, account in enumerate(auth.accounts, 1):
_account = helpers.eos_name_to_string(account.account.actor)
_permission = helpers.eos_name_to_string(account.account.permission)
_account = eos_name_to_string(account.account.actor)
_permission = eos_name_to_string(account.account.permission)
a_header = f"Account #{i}:"
p_header = f"Acc Permission #{i}:"
w_header = f"Account #{i} weight:"
i = str(i)
a_header = "Account #" + i + ":"
p_header = "Acc Permission #" + i + ":"
w_header = "Account #" + i + " weight:"
fields.append((a_header, _account))
fields.append((p_header, _permission))
fields.append((w_header, str(account.weight)))
append((a_header, _account))
append((p_header, _permission))
append((w_header, str(account.weight)))
for i, wait in enumerate(auth.waits, 1):
_wait = str(wait.wait_sec)
_weight = str(wait.weight)
header = f"Delay #{i}"
w_header = f"Delay #{i} weight:"
fields.append((header, f"{_wait} sec"))
fields.append((w_header, _weight))
header = "Delay #" + str(i)
w_header = header + " weight:"
append((header, _wait + " sec"))
append((w_header, _weight))
return fields

View File

@ -1,35 +1,30 @@
from typing import TYPE_CHECKING
from trezor import wire
from trezor.crypto.curve import secp256k1
from trezor.messages import EosPublicKey
from apps.common import paths
from apps.common.keychain import Keychain, auto_keychain
from .helpers import public_key_to_wif
from .layout import require_get_public_key
from apps.common.keychain import auto_keychain
if TYPE_CHECKING:
from trezor.messages import EosGetPublicKey
from trezor.crypto import bip32
def _get_public_key(node: bip32.HDNode) -> tuple[str, bytes]:
seckey = node.private_key()
public_key = secp256k1.publickey(seckey, True)
wif = public_key_to_wif(public_key)
return wif, public_key
from trezor.messages import EosGetPublicKey, EosPublicKey
from apps.common.keychain import Keychain
from trezor.wire import Context
@auto_keychain(__name__)
async def get_public_key(
ctx: wire.Context, msg: EosGetPublicKey, keychain: Keychain
ctx: Context, msg: EosGetPublicKey, keychain: Keychain
) -> EosPublicKey:
from trezor.crypto.curve import secp256k1
from trezor.messages import EosPublicKey
from apps.common import paths
from .helpers import public_key_to_wif
from .layout import require_get_public_key
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
wif, public_key = _get_public_key(node)
public_key = secp256k1.publickey(node.private_key(), True)
wif = public_key_to_wif(public_key)
if msg.show_display:
await require_get_public_key(ctx, wif)
return EosPublicKey(wif_public_key=wif, raw_public_key=public_key)

View File

@ -1,13 +1,12 @@
from typing import TYPE_CHECKING
from trezor import wire
from trezor.crypto import base58
if TYPE_CHECKING:
from trezor.messages import EosAsset
def base58_encode(prefix: str, sig_prefix: str, data: bytes) -> str:
from trezor.crypto import base58
b58 = base58.encode(data + base58.ripemd160_32(data + sig_prefix.encode()))
if sig_prefix:
return prefix + sig_prefix + "_" + b58
@ -45,11 +44,13 @@ def eos_asset_to_string(asset: EosAsset) -> str:
def public_key_to_wif(pub_key: bytes) -> str:
from trezor.wire import DataError
if pub_key[0] == 0x04 and len(pub_key) == 65:
head = b"\x03" if pub_key[64] & 0x01 else b"\x02"
compressed_pub_key = head + pub_key[1:33]
elif pub_key[0] in [0x02, 0x03] and len(pub_key) == 33:
compressed_pub_key = pub_key
else:
raise wire.DataError("invalid public key")
raise DataError("invalid public key")
return base58_encode("EOS", "", compressed_pub_key)

View File

@ -1,18 +1,25 @@
from trezor import ui, wire
from trezor.enums import ButtonRequestType
from trezor.strings import format_plural
from trezor.ui.layouts import confirm_action, show_pubkey
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from trezor.wire import Context
async def require_get_public_key(ctx: wire.Context, public_key: str) -> None:
async def require_get_public_key(ctx: Context, public_key: str) -> None:
from trezor.ui.layouts import show_pubkey
await show_pubkey(ctx, public_key)
async def require_sign_tx(ctx: wire.Context, num_actions: int) -> None:
async def require_sign_tx(ctx: Context, num_actions: int) -> None:
from trezor import ui
from trezor.enums import ButtonRequestType
from trezor.strings import format_plural
from trezor.ui.layouts import confirm_action
await confirm_action(
ctx,
"confirm_tx",
title="Sign transaction",
"Sign transaction",
description="You are about to sign {}.",
description_param=format_plural("{count} {plural}", num_actions, "action"),
icon=ui.ICON_SEND,

View File

@ -1,36 +1,50 @@
from typing import TYPE_CHECKING
from trezor import wire
from apps.common.keychain import auto_keychain
if TYPE_CHECKING:
from trezor.wire import Context
from trezor.messages import EosSignTx, EosSignedTx
from apps.common.keychain import Keychain
@auto_keychain(__name__)
async def sign_tx(ctx: Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx:
from trezor.wire import DataError
from trezor.crypto.curve import secp256k1
from trezor.crypto.hashlib import sha256
from trezor.messages import EosSignedTx, EosTxActionAck, EosTxActionRequest
from trezor.utils import HashWriter
from apps.common import paths
from apps.common.keychain import Keychain, auto_keychain
from . import writers
from .writers import write_uvarint, write_header, write_bytes_fixed
from .actions import process_action
from .helpers import base58_encode
from .layout import require_sign_tx
if TYPE_CHECKING:
from trezor.messages import EosSignTx
num_actions = msg.num_actions # local_cache_attribute
@auto_keychain(__name__)
async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosSignedTx:
if not msg.num_actions:
raise wire.DataError("No actions")
if not num_actions:
raise DataError("No actions")
await paths.validate_path(ctx, keychain, msg.address_n)
node = keychain.derive(msg.address_n)
sha = HashWriter(sha256())
await _init(ctx, sha, msg)
await _actions(ctx, sha, msg.num_actions)
writers.write_uvarint(sha, 0)
writers.write_bytes_fixed(sha, bytearray(32), 32)
# init
write_bytes_fixed(sha, msg.chain_id, 32)
write_header(sha, msg.header)
write_uvarint(sha, 0)
write_uvarint(sha, num_actions)
await require_sign_tx(ctx, num_actions)
# actions
for _ in range(num_actions):
action = await ctx.call(EosTxActionRequest(), EosTxActionAck)
await process_action(ctx, sha, action)
write_uvarint(sha, 0)
write_bytes_fixed(sha, bytearray(32), 32)
digest = sha.get_digest()
signature = secp256k1.sign(
@ -38,18 +52,3 @@ async def sign_tx(ctx: wire.Context, msg: EosSignTx, keychain: Keychain) -> EosS
)
return EosSignedTx(signature=base58_encode("SIG_", "K1", signature))
async def _init(ctx: wire.Context, sha: HashWriter, msg: EosSignTx) -> None:
writers.write_bytes_fixed(sha, msg.chain_id, 32)
writers.write_header(sha, msg.header)
writers.write_uvarint(sha, 0)
writers.write_uvarint(sha, msg.num_actions)
await require_sign_tx(ctx, msg.num_actions)
async def _actions(ctx: wire.Context, sha: HashWriter, num_actions: int) -> None:
for _ in range(num_actions):
action = await ctx.call(EosTxActionRequest(), EosTxActionAck)
await process_action(ctx, sha, action)

View File

@ -1,7 +1,5 @@
from typing import TYPE_CHECKING
from trezor import wire
from apps.common.writers import (
write_bytes_fixed,
write_bytes_unchecked,
@ -36,11 +34,13 @@ if TYPE_CHECKING:
def write_auth(w: Writer, auth: EosAuthorization) -> None:
from trezor.wire import DataError
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.")
raise DataError("Key must be provided explicitly.")
write_uvarint(w, key.type)
write_bytes_fixed(w, key.key, 33)
write_uint16_le(w, key.weight)
@ -91,14 +91,13 @@ def write_action_sellram(w: Writer, msg: EosActionSellRam) -> None:
def write_action_delegate(w: Writer, msg: EosActionDelegate) -> None:
write_uint64_le(w, msg.sender)
write_uint64_le(w, msg.receiver)
write_asset(w, msg.net_quantity)
write_asset(w, msg.cpu_quantity)
write_action_undelegate(w, msg)
write_uint8(w, 1 if msg.transfer else 0)
def write_action_undelegate(w: Writer, msg: EosActionUndelegate) -> None:
def write_action_undelegate(
w: Writer, msg: EosActionUndelegate | EosActionDelegate
) -> None:
write_uint64_le(w, msg.sender)
write_uint64_le(w, msg.receiver)
write_asset(w, msg.net_quantity)
@ -118,25 +117,26 @@ def write_action_voteproducer(w: Writer, msg: EosActionVoteProducer) -> None:
def write_action_updateauth(w: Writer, msg: EosActionUpdateAuth) -> None:
write_uint64_le(w, msg.account)
write_uint64_le(w, msg.permission)
write_action_deleteauth(w, msg)
write_uint64_le(w, msg.parent)
write_auth(w, msg.auth)
def write_action_deleteauth(w: Writer, msg: EosActionDeleteAuth) -> None:
def write_action_deleteauth(
w: Writer, msg: EosActionDeleteAuth | EosActionUpdateAuth
) -> None:
write_uint64_le(w, msg.account)
write_uint64_le(w, msg.permission)
def write_action_linkauth(w: Writer, msg: EosActionLinkAuth) -> None:
write_uint64_le(w, msg.account)
write_uint64_le(w, msg.code)
write_uint64_le(w, msg.type)
write_action_unlinkauth(w, msg)
write_uint64_le(w, msg.requirement)
def write_action_unlinkauth(w: Writer, msg: EosActionUnlinkAuth) -> None:
def write_action_unlinkauth(
w: Writer, msg: EosActionUnlinkAuth | EosActionLinkAuth
) -> None:
write_uint64_le(w, msg.account)
write_uint64_le(w, msg.code)
write_uint64_le(w, msg.type)

View File

@ -1,7 +1,7 @@
from common import *
if not utils.BITCOIN_ONLY:
from apps.eos.actions import check_action
from apps.eos.actions import _check_action
from trezor.messages import EosTxActionAck
@ -9,43 +9,43 @@ if not utils.BITCOIN_ONLY:
class TestEosActions(unittest.TestCase):
def test_check_action(self):
# return 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)
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(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)
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__':

View File

@ -1,13 +1,20 @@
from common import *
from trezor.crypto import bip32, bip39
from apps.common.paths import HARDENED
from trezor.crypto.curve import secp256k1
if not utils.BITCOIN_ONLY:
from apps.eos.get_public_key import _get_public_key
from apps.eos.helpers import public_key_to_wif
# NOTE: copy-pasted from apps.eos.get_public_key
def _get_public_key(node: bip32.HDNode) -> tuple[str, bytes]:
seckey = node.private_key()
public_key = secp256k1.publickey(seckey, True)
wif = public_key_to_wif(public_key)
return wif, public_key
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
class TestEosGetPublicKey(unittest.TestCase):
def test_get_public_key_scheme(self):