mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-29 09:38:08 +00:00
made requested changes
This commit is contained in:
parent
c0e5a32dec
commit
fd95ff0531
@ -126,19 +126,24 @@ message TezosSignTx {
|
||||
* Structure representing information for proposal
|
||||
*/
|
||||
message TezosProposalOp {
|
||||
optional bytes source = 1;
|
||||
optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID
|
||||
optional uint64 period = 2;
|
||||
optional uint64 bytes_in_next_field = 3;
|
||||
optional bytes proposals = 4;
|
||||
repeated bytes proposals = 4;
|
||||
}
|
||||
/**
|
||||
* Structure representing information for ballot
|
||||
*/
|
||||
message TezosBallotOp {
|
||||
optional bytes source = 1;
|
||||
optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID
|
||||
optional uint64 period = 2;
|
||||
optional bytes proposal = 3;
|
||||
optional bytes ballot = 4;
|
||||
optional TezosBallotType ballot = 4;
|
||||
|
||||
enum TezosBallotType {
|
||||
Yay = 0;
|
||||
Nay = 1;
|
||||
Pass = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,13 @@ def write_uint16_le(w: bytearray, n: int) -> int:
|
||||
return 2
|
||||
|
||||
|
||||
def write_uint16_be(w: bytearray, n: int):
|
||||
ensure(0 <= n <= 0xFFFF)
|
||||
w.append((n >> 8) & 0xFF)
|
||||
w.append(n & 0xFF)
|
||||
return 2
|
||||
|
||||
|
||||
def write_uint32_le(w: bytearray, n: int) -> int:
|
||||
ensure(0 <= n <= 0xFFFFFFFF)
|
||||
w.append(n & 0xFF)
|
||||
|
@ -3,6 +3,7 @@ from micropython import const
|
||||
from trezor.crypto import base58
|
||||
|
||||
from apps.common import HARDENED
|
||||
from apps.common.writers import write_uint8
|
||||
|
||||
TEZOS_AMOUNT_DIVISIBILITY = const(6)
|
||||
TEZOS_ED25519_ADDRESS_PREFIX = "tz1"
|
||||
@ -21,7 +22,7 @@ TEZOS_PREFIX_BYTES = {
|
||||
"edsig": [9, 245, 205, 134, 18],
|
||||
# operation hash
|
||||
"o": [5, 116],
|
||||
# protocola hash
|
||||
# protocol hash
|
||||
"P": [2, 170],
|
||||
}
|
||||
|
||||
@ -45,7 +46,8 @@ def validate_full_path(path: list) -> bool:
|
||||
Validates derivation path to equal 44'/1729'/a',
|
||||
where `a` is an account index from 0 to 1 000 000.
|
||||
"""
|
||||
if len(path) != 3:
|
||||
length = len(path)
|
||||
if length < 3 or length > 4:
|
||||
return False
|
||||
if path[0] != 44 | HARDENED:
|
||||
return False
|
||||
@ -53,4 +55,13 @@ def validate_full_path(path: list) -> bool:
|
||||
return False
|
||||
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
|
||||
return False
|
||||
if length > 3 and (path[3] < HARDENED or path[3] > 1000000 | HARDENED):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def write_bool(w: bytearray, boolean: bool):
|
||||
if boolean:
|
||||
write_uint8(w, 255)
|
||||
else:
|
||||
write_uint8(w, 0)
|
||||
|
@ -79,18 +79,11 @@ def format_tezos_amount(value):
|
||||
return formatted_value + " XTZ"
|
||||
|
||||
|
||||
async def require_confirm_proposal(ctx, proposals):
|
||||
text = Text("Submit proposal", ui.ICON_SEND, icon_color=ui.PURPLE)
|
||||
text.bold("Proposal:")
|
||||
text.mono(*split_proposal(proposals[0]))
|
||||
await require_confirm(ctx, text, ButtonRequestType.SignTx)
|
||||
|
||||
|
||||
async def require_confirm_ballot(ctx, proposal, ballot):
|
||||
text = Text("Submit ballot", ui.ICON_SEND, icon_color=ui.PURPLE)
|
||||
text.bold("Ballot: {}".format(ballot))
|
||||
text.bold("Proposal:")
|
||||
text.mono(*split_proposal(proposal[0]))
|
||||
text.mono(*split_proposal(proposal))
|
||||
await require_confirm(ctx, text, ButtonRequestType.SignTx)
|
||||
|
||||
|
||||
@ -98,15 +91,15 @@ async def require_confirm_ballot(ctx, proposal, ballot):
|
||||
async def show_proposals(ctx, proposals):
|
||||
first_page = const(0)
|
||||
pages = proposals
|
||||
title = "Submit proposals" if len(proposals) > 1 else "Submit proposal"
|
||||
|
||||
paginator = paginate(show_proposal_page, len(pages), first_page, pages)
|
||||
paginator = paginate(show_proposal_page, len(pages), first_page, pages, title)
|
||||
return await ctx.wait(paginator)
|
||||
|
||||
|
||||
@ui.layout
|
||||
async def show_proposal_page(page: int, page_count: int, pages: list):
|
||||
|
||||
text = Text("Submit proposals", ui.ICON_SEND, icon_color=ui.PURPLE)
|
||||
async def show_proposal_page(page: int, page_count: int, pages: list, title: str):
|
||||
text = Text(title, ui.ICON_SEND, icon_color=ui.PURPLE)
|
||||
text.bold("Proposal {}: ".format(page + 1))
|
||||
text.mono(*split_proposal(pages[page]))
|
||||
content = Scrollpage(text, page, page_count)
|
||||
|
@ -3,18 +3,16 @@ from micropython import const
|
||||
from trezor import wire
|
||||
from trezor.crypto import hashlib
|
||||
from trezor.crypto.curve import ed25519
|
||||
from trezor.messages import TezosContractType
|
||||
from trezor.messages import TezosContractType, TezosBallotType
|
||||
from trezor.messages.TezosSignedTx import TezosSignedTx
|
||||
|
||||
from apps.common import paths
|
||||
from apps.tezos import CURVE, helpers, layout
|
||||
from apps.tezos.writers import (
|
||||
write_bool,
|
||||
from apps.common.writers import (
|
||||
write_bytes,
|
||||
write_uint8,
|
||||
write_uint16,
|
||||
write_uint32,
|
||||
write_uint64,
|
||||
write_uint16_be,
|
||||
write_uint32_be,
|
||||
)
|
||||
|
||||
PROPOSAL_LENGTH = const(32)
|
||||
@ -65,12 +63,7 @@ async def sign_tx(ctx, msg, keychain):
|
||||
|
||||
elif msg.proposal is not None:
|
||||
proposed_protocols = _get_protocol_hash_from_msg(msg.proposal.proposals)
|
||||
|
||||
# byte count larger than PROPOSAL_LENGTH indicates more than 1 proposal, use paginated screen
|
||||
if msg.proposal.bytes_in_next_field > PROPOSAL_LENGTH:
|
||||
await layout.show_proposals(ctx, proposed_protocols)
|
||||
else:
|
||||
await layout.require_confirm_proposal(ctx, proposed_protocols)
|
||||
await layout.show_proposals(ctx, proposed_protocols)
|
||||
|
||||
elif msg.ballot is not None:
|
||||
proposed_protocol = _get_protocol_hash_from_msg(msg.ballot.proposal)
|
||||
@ -127,25 +120,20 @@ def _get_address_from_contract(address):
|
||||
|
||||
|
||||
def _get_protocol_hash_from_msg(proposals):
|
||||
# split the proposals
|
||||
proposal_list = list(
|
||||
[
|
||||
proposals[i : i + PROPOSAL_LENGTH]
|
||||
for i in range(0, len(proposals), PROPOSAL_LENGTH)
|
||||
]
|
||||
)
|
||||
print(proposals)
|
||||
if type(proposals) is not list:
|
||||
return helpers.base58_encode_check(proposals, prefix="P")
|
||||
return [
|
||||
helpers.base58_encode_check(proposal, prefix="P") for proposal in proposal_list
|
||||
helpers.base58_encode_check(proposal, prefix="P") for proposal in proposals
|
||||
]
|
||||
|
||||
|
||||
def _get_ballot(encoded_ballot):
|
||||
encoded_ballot = int(encoded_ballot[0])
|
||||
if encoded_ballot == 0:
|
||||
def _get_ballot(ballot):
|
||||
if ballot == TezosBallotType.Yay:
|
||||
return "yay"
|
||||
elif encoded_ballot == 1:
|
||||
elif ballot == TezosBallotType.Nay:
|
||||
return "nay"
|
||||
elif encoded_ballot == 2:
|
||||
elif ballot == TezosBallotType.Pass:
|
||||
return "pass"
|
||||
|
||||
|
||||
@ -169,8 +157,8 @@ def _get_operation_bytes(w: bytearray, msg):
|
||||
_encode_common(w, msg.origination, "origination")
|
||||
write_bytes(w, msg.origination.manager_pubkey)
|
||||
_encode_zarith(w, msg.origination.balance)
|
||||
_encode_bool(w, msg.origination.spendable)
|
||||
_encode_bool(w, msg.origination.delegatable)
|
||||
helpers.write_bool(w, msg.origination.spendable)
|
||||
helpers.write_bool(w, msg.origination.delegatable)
|
||||
_encode_data_with_bool_prefix(w, msg.origination.delegate)
|
||||
_encode_data_with_bool_prefix(w, msg.origination.script)
|
||||
# delegation operation
|
||||
@ -198,19 +186,12 @@ def _encode_contract_id(w: bytearray, contract_id):
|
||||
write_bytes(w, contract_id.hash)
|
||||
|
||||
|
||||
def _encode_bool(w: bytearray, boolean):
|
||||
if boolean:
|
||||
write_uint8(w, 255)
|
||||
else:
|
||||
write_uint8(w, 0)
|
||||
|
||||
|
||||
def _encode_data_with_bool_prefix(w: bytearray, data):
|
||||
if data:
|
||||
_encode_bool(w, True)
|
||||
helpers.write_bool(w, True)
|
||||
write_bytes(w, data)
|
||||
else:
|
||||
_encode_bool(w, False)
|
||||
helpers.write_bool(w, False)
|
||||
|
||||
|
||||
def _encode_zarith(w: bytearray, num):
|
||||
@ -230,9 +211,10 @@ def _encode_proposal(w: bytearray, proposal):
|
||||
|
||||
write_uint8(w, proposal_tag)
|
||||
write_bytes(w, proposal.source)
|
||||
write_uint32(w, proposal.period)
|
||||
write_uint32(w, proposal.bytes_in_next_field)
|
||||
write_bytes(w, proposal.proposals)
|
||||
write_uint32_be(w, proposal.period)
|
||||
write_uint32_be(w, _get_proposals_bytecount(proposal.proposals))
|
||||
for proposal_hash in proposal.proposals:
|
||||
write_bytes(w, proposal_hash)
|
||||
|
||||
|
||||
def _encode_ballot(w: bytearray, ballot):
|
||||
@ -240,6 +222,10 @@ def _encode_ballot(w: bytearray, ballot):
|
||||
|
||||
write_uint8(w, ballot_tag)
|
||||
write_bytes(w, ballot.source)
|
||||
write_uint32(w, ballot.period)
|
||||
write_uint32_be(w, ballot.period)
|
||||
write_bytes(w, ballot.proposal)
|
||||
write_bytes(w, ballot.ballot)
|
||||
write_uint8(w, ballot.ballot)
|
||||
|
||||
|
||||
def _get_proposals_bytecount(proposals):
|
||||
return len(proposals) * PROPOSAL_LENGTH
|
||||
|
@ -10,7 +10,7 @@ class TezosBallotOp(p.MessageType):
|
||||
source: bytes = None,
|
||||
period: int = None,
|
||||
proposal: bytes = None,
|
||||
ballot: bytes = None,
|
||||
ballot: int = None,
|
||||
) -> None:
|
||||
self.source = source
|
||||
self.period = period
|
||||
@ -23,5 +23,5 @@ class TezosBallotOp(p.MessageType):
|
||||
1: ('source', p.BytesType, 0),
|
||||
2: ('period', p.UVarintType, 0),
|
||||
3: ('proposal', p.BytesType, 0),
|
||||
4: ('ballot', p.BytesType, 0),
|
||||
4: ('ballot', p.UVarintType, 0),
|
||||
}
|
||||
|
5
core/src/trezor/messages/TezosBallotType.py
Normal file
5
core/src/trezor/messages/TezosBallotType.py
Normal file
@ -0,0 +1,5 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
Yay = 0
|
||||
Nay = 1
|
||||
Pass = 2
|
@ -2,6 +2,12 @@
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class TezosProposalOp(p.MessageType):
|
||||
|
||||
@ -9,19 +15,16 @@ class TezosProposalOp(p.MessageType):
|
||||
self,
|
||||
source: bytes = None,
|
||||
period: int = None,
|
||||
bytes_in_next_field: int = None,
|
||||
proposals: bytes = None,
|
||||
proposals: List[bytes] = None,
|
||||
) -> None:
|
||||
self.source = source
|
||||
self.period = period
|
||||
self.bytes_in_next_field = bytes_in_next_field
|
||||
self.proposals = proposals
|
||||
self.proposals = proposals if proposals is not None else []
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('source', p.BytesType, 0),
|
||||
2: ('period', p.UVarintType, 0),
|
||||
3: ('bytes_in_next_field', p.UVarintType, 0),
|
||||
4: ('proposals', p.BytesType, 0),
|
||||
4: ('proposals', p.BytesType, p.FLAG_REPEATED),
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ from trezorlib.tools import parse_path
|
||||
from .common import TrezorTest
|
||||
|
||||
TEZOS_PATH = parse_path("m/44'/1729'/0'")
|
||||
TEZOS_PATH_10 = parse_path("m/44'/1729'/10'")
|
||||
|
||||
|
||||
@pytest.mark.tezos
|
||||
@ -194,3 +195,140 @@ class TestMsgTezosSignTx(TrezorTest):
|
||||
assert (
|
||||
resp.operation_hash == "oocgc3hyKsGHPsw6WFWJpWT8jBwQLtebQAXF27KNisThkzoj635"
|
||||
)
|
||||
|
||||
def test_tezos_sign_tx_proposal(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
resp = tezos.sign_tx(
|
||||
self.client,
|
||||
TEZOS_PATH_10,
|
||||
dict_to_proto(
|
||||
messages.TezosSignTx,
|
||||
{
|
||||
"branch": "dee04042c0832d68a43699b2001c0a38065436eb05e578071a763e1972d0bc81",
|
||||
"proposal": {
|
||||
"source": "005f450441f41ee11eee78a31d1e1e55627c783bd6",
|
||||
"period": 17,
|
||||
"proposals": ["dfa974df171c2dad9a9b8f25d99af41fd9702ce5d04521d2f9943c84d88aa572"],
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
assert (
|
||||
resp.signature
|
||||
== "edsigtfY16R32k2WVMYfFr7ymnro4ib5zMckk28vsuViYNN77DJAvCJLRNArd9L531pUCxT4YdcvCvBym5dhcZ1rknEVm6yZ8bB"
|
||||
)
|
||||
assert (
|
||||
resp.sig_op_contents.hex()
|
||||
== "dee04042c0832d68a43699b2001c0a38065436eb05e578071a763e1972d0bc8105005f450441f41ee11eee78a31d1e1e55627c783bd60000001100000020dfa974df171c2dad9a9b8f25d99af41fd9702ce5d04521d2f9943c84d88aa5723b12621296a679b3a74ea790df5347995a76e20a09e76590baaacf4e09341965a04123f5cbbba8427f045b5f7d59157a3098e44839babe7c247d19b58bbb2405"
|
||||
)
|
||||
assert (
|
||||
resp.operation_hash == "opLqntFUu984M7LnGsFvfGW6kWe9QjAz4AfPDqQvwJ1wPM4Si4c"
|
||||
)
|
||||
|
||||
def test_tezos_sign_tx_multiple_proposals(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
resp = tezos.sign_tx(
|
||||
self.client,
|
||||
TEZOS_PATH_10,
|
||||
dict_to_proto(
|
||||
messages.TezosSignTx,
|
||||
{
|
||||
"branch": "7e0be36a90c663c73c60da3889ffefff1383fb65cc29f0639f173d8f95a52df7",
|
||||
"proposal": {
|
||||
"source": "005f450441f41ee11eee78a31d1e1e55627c783bd6",
|
||||
"period": 17,
|
||||
"proposals": ["2a6ff28ab4d0ccb18f7129aaaf9a4b8027d794f2562849665fdb6999db2a4e57",
|
||||
"47cd60c09ab8437cc9fe19add494dce1b9844100f660f02ce77510a0c66d2762"],
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
assert (
|
||||
resp.signature
|
||||
== "edsigu6GAjhiWAQ64ctWTGEDYAZ16tYzLgzWzqc4CUyixK4FGRE8YUBVzFaVJ2fUCexZjZLMLdiNZGcUdzeL1bQhZ2h5oLrh7pA"
|
||||
)
|
||||
assert (
|
||||
resp.sig_op_contents.hex()
|
||||
== "7e0be36a90c663c73c60da3889ffefff1383fb65cc29f0639f173d8f95a52df705005f450441f41ee11eee78a31d1e1e55627c783bd600000011000000402a6ff28ab4d0ccb18f7129aaaf9a4b8027d794f2562849665fdb6999db2a4e5747cd60c09ab8437cc9fe19add494dce1b9844100f660f02ce77510a0c66d2762f813361ac00ada7e3256f23973ae25b112229476a3cb3e506fe929ea1e9358299fed22178d1be689cddeedd1f303abfef859b664f159a528576a1c807079f005"
|
||||
)
|
||||
assert (
|
||||
resp.operation_hash == "onobSyNgiitGXxSVFJN6949MhUomkkxvH4ZJ2owgWwNeDdntF9Y"
|
||||
)
|
||||
|
||||
|
||||
def test_tezos_sing_tx_ballot_yay(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
resp = tezos.sign_tx(
|
||||
self.client,
|
||||
TEZOS_PATH_10,
|
||||
dict_to_proto(
|
||||
messages.TezosSignTx,
|
||||
{
|
||||
"branch": "3a8f60c4cd394cee5b50136c7fc8cb157e8aaa476a9e5c68709be6fc1cdb5395",
|
||||
"ballot": {
|
||||
"source": "0002298c03ed7d454a101eb7022bc95f7e5f41ac78",
|
||||
"period": 2,
|
||||
"proposal": "def7ed9c84af23ab37ebb60dd83cd103d1272ad6c63d4c05931567e65ed027e3",
|
||||
"ballot": 0
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
assert (
|
||||
resp.signature
|
||||
== "edsigtkxNm6YXwtV24DqeuimeZFTeFCn2jDYheSsXT4rHMcEjNvzsiSo55nVyVsQxtEe8M7U4PWJWT4rGYYGckQCgtkNJkd2roX"
|
||||
)
|
||||
|
||||
def test_tezos_sing_tx_ballot_nay(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
resp = tezos.sign_tx(
|
||||
self.client,
|
||||
TEZOS_PATH_10,
|
||||
dict_to_proto(
|
||||
messages.TezosSignTx,
|
||||
{
|
||||
"branch": "3a8f60c4cd394cee5b50136c7fc8cb157e8aaa476a9e5c68709be6fc1cdb5395",
|
||||
"ballot": {
|
||||
"source": "0002298c03ed7d454a101eb7022bc95f7e5f41ac78",
|
||||
"period": 2,
|
||||
"proposal": "def7ed9c84af23ab37ebb60dd83cd103d1272ad6c63d4c05931567e65ed027e3",
|
||||
"ballot": 1
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
assert (
|
||||
resp.signature
|
||||
== "edsigtqLaizfF6Cfc2JQL7TrsyniGhpZEojZAKMFW6AeudaUoU8KGXEHJH69Q4Lf27qFyUSTfbeHNnnCt69SGEPWkmpkgkgqMbL"
|
||||
)
|
||||
|
||||
def test_tezos_sing_tx_ballot_pass(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
resp = tezos.sign_tx(
|
||||
self.client,
|
||||
TEZOS_PATH_10,
|
||||
dict_to_proto(
|
||||
messages.TezosSignTx,
|
||||
{
|
||||
"branch": "3a8f60c4cd394cee5b50136c7fc8cb157e8aaa476a9e5c68709be6fc1cdb5395",
|
||||
"ballot": {
|
||||
"source": "0002298c03ed7d454a101eb7022bc95f7e5f41ac78",
|
||||
"period": 2,
|
||||
"proposal": "def7ed9c84af23ab37ebb60dd83cd103d1272ad6c63d4c05931567e65ed027e3",
|
||||
"ballot": 2
|
||||
},
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
assert (
|
||||
resp.signature
|
||||
== "edsigu6YX7EegPwrpcEbdNQsNhrRiEagBNGJBmFamP4mixZZw1UynhahGQ8RNiZLSUVLERUZwygrsSVenBqXGt9VnknTxtzjKzv"
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user