1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-21 23:18:13 +00:00

made requested changes

This commit is contained in:
Adrian Nagy 2019-04-16 19:20:40 +02:00
parent c0e5a32dec
commit fd95ff0531
9 changed files with 216 additions and 68 deletions

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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),
}

View File

@ -0,0 +1,5 @@
# Automatically generated by pb2py
# fmt: off
Yay = 0
Nay = 1
Pass = 2

View File

@ -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),
}

View File

@ -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"
)