mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
commit
c9f380eae4
@ -55,6 +55,8 @@ message TezosSignTx {
|
||||
optional TezosTransactionOp transaction = 4; // Tezos transaction operation
|
||||
optional TezosOriginationOp origination = 5; // Tezos origination operation
|
||||
optional TezosDelegationOp delegation = 6; // Tezos delegation operation
|
||||
optional TezosProposalOp proposal = 7; // Tezos proposal operation
|
||||
optional TezosBallotOp ballot = 8; // Tezos ballot operation
|
||||
/*
|
||||
* Tezos contract ID
|
||||
*/
|
||||
@ -120,6 +122,29 @@ message TezosSignTx {
|
||||
optional uint64 storage_limit = 5;
|
||||
optional bytes delegate = 6;
|
||||
}
|
||||
/**
|
||||
* Structure representing information for proposal
|
||||
*/
|
||||
message TezosProposalOp {
|
||||
optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID
|
||||
optional uint64 period = 2;
|
||||
repeated bytes proposals = 4;
|
||||
}
|
||||
/**
|
||||
* Structure representing information for ballot
|
||||
*/
|
||||
message TezosBallotOp {
|
||||
optional bytes source = 1; //Contains only public_key_hash, not to be confused with TezosContractID
|
||||
optional uint64 period = 2;
|
||||
optional bytes proposal = 3;
|
||||
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,6 +22,8 @@ TEZOS_PREFIX_BYTES = {
|
||||
"edsig": [9, 245, 205, 134, 18],
|
||||
# operation hash
|
||||
"o": [5, 116],
|
||||
# protocol hash
|
||||
"P": [2, 170],
|
||||
}
|
||||
|
||||
|
||||
@ -42,13 +45,29 @@ 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.
|
||||
Additional component added to allow ledger migration
|
||||
44'/1729'/0'/b' where `b` 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
|
||||
if path[1] != 1729 | HARDENED:
|
||||
return False
|
||||
if length == 3:
|
||||
if path[2] < HARDENED or path[2] > 1000000 | HARDENED:
|
||||
return False
|
||||
if length == 4:
|
||||
if path[2] != 0 | HARDENED:
|
||||
return False
|
||||
if 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)
|
||||
|
@ -1,5 +1,10 @@
|
||||
from trezor import ui
|
||||
from trezor.messages import ButtonRequestType
|
||||
from micropython import const
|
||||
|
||||
from trezor import ui, wire
|
||||
from trezor.messages import ButtonRequestType, MessageType
|
||||
from trezor.messages.ButtonRequest import ButtonRequest
|
||||
from trezor.ui.confirm import CANCELLED, ConfirmDialog
|
||||
from trezor.ui.scroll import Scrollpage, animate_swipe, paginate
|
||||
from trezor.ui.text import Text
|
||||
from trezor.utils import chunks, format_amount
|
||||
|
||||
@ -66,6 +71,45 @@ def split_address(address):
|
||||
return chunks(address, 18)
|
||||
|
||||
|
||||
def split_proposal(proposal):
|
||||
return chunks(proposal, 17)
|
||||
|
||||
|
||||
def format_tezos_amount(value):
|
||||
formatted_value = format_amount(value, TEZOS_AMOUNT_DIVISIBILITY)
|
||||
return formatted_value + " XTZ"
|
||||
|
||||
|
||||
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))
|
||||
await require_confirm(ctx, text, ButtonRequestType.SignTx)
|
||||
|
||||
|
||||
# use, when there are more then one proposals in one operation
|
||||
async def require_confirm_proposals(ctx, proposals):
|
||||
await ctx.call(ButtonRequest(code=ButtonRequestType.SignTx), MessageType.ButtonAck)
|
||||
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, title)
|
||||
return await ctx.wait(paginator)
|
||||
|
||||
|
||||
@ui.layout
|
||||
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)
|
||||
|
||||
if page + 1 >= page_count:
|
||||
confirm = await ConfirmDialog(content)
|
||||
if confirm == CANCELLED:
|
||||
raise wire.ActionCancelled("Cancelled")
|
||||
else:
|
||||
content.render()
|
||||
await animate_swipe()
|
||||
|
@ -1,13 +1,22 @@
|
||||
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 TezosBallotType, TezosContractType
|
||||
from trezor.messages.TezosSignedTx import TezosSignedTx
|
||||
|
||||
from apps.common import paths
|
||||
from apps.common.writers import write_bytes, write_uint8
|
||||
from apps.common.writers import (
|
||||
write_bytes,
|
||||
write_uint8,
|
||||
write_uint16_be,
|
||||
write_uint32_be,
|
||||
)
|
||||
from apps.tezos import CURVE, helpers, layout
|
||||
|
||||
PROPOSAL_LENGTH = const(32)
|
||||
|
||||
|
||||
async def sign_tx(ctx, msg, keychain):
|
||||
await paths.validate_path(
|
||||
@ -52,6 +61,15 @@ async def sign_tx(ctx, msg, keychain):
|
||||
ctx, source, msg.delegation.fee
|
||||
)
|
||||
|
||||
elif msg.proposal is not None:
|
||||
proposed_protocols = [_get_protocol_hash(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)
|
||||
await layout.require_confirm_ballot(ctx, proposed_protocol, submitted_ballot)
|
||||
|
||||
else:
|
||||
raise wire.DataError("Invalid operation")
|
||||
|
||||
@ -101,11 +119,24 @@ def _get_address_from_contract(address):
|
||||
raise wire.DataError("Invalid contract type")
|
||||
|
||||
|
||||
def _get_protocol_hash(proposal):
|
||||
return helpers.base58_encode_check(proposal, prefix="P")
|
||||
|
||||
|
||||
def _get_ballot(ballot):
|
||||
if ballot == TezosBallotType.Yay:
|
||||
return "yay"
|
||||
elif ballot == TezosBallotType.Nay:
|
||||
return "nay"
|
||||
elif ballot == TezosBallotType.Pass:
|
||||
return "pass"
|
||||
|
||||
|
||||
def _get_operation_bytes(w: bytearray, msg):
|
||||
write_bytes(w, msg.branch)
|
||||
|
||||
# when the account sends first operation in lifetime,
|
||||
# we need to reveal its publickey
|
||||
# we need to reveal its public key
|
||||
if msg.reveal is not None:
|
||||
_encode_common(w, msg.reveal, "reveal")
|
||||
write_bytes(w, msg.reveal.public_key)
|
||||
@ -121,14 +152,18 @@ 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
|
||||
elif msg.delegation is not None:
|
||||
_encode_common(w, msg.delegation, "delegation")
|
||||
_encode_data_with_bool_prefix(w, msg.delegation.delegate)
|
||||
elif msg.proposal is not None:
|
||||
_encode_proposal(w, msg.proposal)
|
||||
elif msg.ballot is not None:
|
||||
_encode_ballot(w, msg.ballot)
|
||||
|
||||
|
||||
def _encode_common(w: bytearray, operation, str_operation):
|
||||
@ -146,19 +181,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):
|
||||
@ -171,3 +199,24 @@ def _encode_zarith(w: bytearray, num):
|
||||
break
|
||||
|
||||
write_uint8(w, 128 | byte)
|
||||
|
||||
|
||||
def _encode_proposal(w: bytearray, proposal):
|
||||
proposal_tag = 5
|
||||
|
||||
write_uint8(w, proposal_tag)
|
||||
write_bytes(w, proposal.source)
|
||||
write_uint32_be(w, proposal.period)
|
||||
write_uint32_be(w, len(proposal.proposals) * PROPOSAL_LENGTH)
|
||||
for proposal_hash in proposal.proposals:
|
||||
write_bytes(w, proposal_hash)
|
||||
|
||||
|
||||
def _encode_ballot(w: bytearray, ballot):
|
||||
ballot_tag = 6
|
||||
|
||||
write_uint8(w, ballot_tag)
|
||||
write_bytes(w, ballot.source)
|
||||
write_uint32_be(w, ballot.period)
|
||||
write_bytes(w, ballot.proposal)
|
||||
write_uint8(w, ballot.ballot)
|
||||
|
27
core/src/trezor/messages/TezosBallotOp.py
Normal file
27
core/src/trezor/messages/TezosBallotOp.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class TezosBallotOp(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source: bytes = None,
|
||||
period: int = None,
|
||||
proposal: bytes = None,
|
||||
ballot: int = None,
|
||||
) -> None:
|
||||
self.source = source
|
||||
self.period = period
|
||||
self.proposal = proposal
|
||||
self.ballot = ballot
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
return {
|
||||
1: ('source', p.BytesType, 0),
|
||||
2: ('period', p.UVarintType, 0),
|
||||
3: ('proposal', 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
|
30
core/src/trezor/messages/TezosProposalOp.py
Normal file
30
core/src/trezor/messages/TezosProposalOp.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Automatically generated by pb2py
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
if __debug__:
|
||||
try:
|
||||
from typing import List
|
||||
except ImportError:
|
||||
List = None # type: ignore
|
||||
|
||||
|
||||
class TezosProposalOp(p.MessageType):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source: bytes = None,
|
||||
period: int = None,
|
||||
proposals: List[bytes] = None,
|
||||
) -> None:
|
||||
self.source = source
|
||||
self.period = period
|
||||
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),
|
||||
4: ('proposals', p.BytesType, p.FLAG_REPEATED),
|
||||
}
|
@ -2,8 +2,10 @@
|
||||
# fmt: off
|
||||
import protobuf as p
|
||||
|
||||
from .TezosBallotOp import TezosBallotOp
|
||||
from .TezosDelegationOp import TezosDelegationOp
|
||||
from .TezosOriginationOp import TezosOriginationOp
|
||||
from .TezosProposalOp import TezosProposalOp
|
||||
from .TezosRevealOp import TezosRevealOp
|
||||
from .TezosTransactionOp import TezosTransactionOp
|
||||
|
||||
@ -25,6 +27,8 @@ class TezosSignTx(p.MessageType):
|
||||
transaction: TezosTransactionOp = None,
|
||||
origination: TezosOriginationOp = None,
|
||||
delegation: TezosDelegationOp = None,
|
||||
proposal: TezosProposalOp = None,
|
||||
ballot: TezosBallotOp = None,
|
||||
) -> None:
|
||||
self.address_n = address_n if address_n is not None else []
|
||||
self.branch = branch
|
||||
@ -32,6 +36,8 @@ class TezosSignTx(p.MessageType):
|
||||
self.transaction = transaction
|
||||
self.origination = origination
|
||||
self.delegation = delegation
|
||||
self.proposal = proposal
|
||||
self.ballot = ballot
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls):
|
||||
@ -42,4 +48,6 @@ class TezosSignTx(p.MessageType):
|
||||
4: ('transaction', TezosTransactionOp, 0),
|
||||
5: ('origination', TezosOriginationOp, 0),
|
||||
6: ('delegation', TezosDelegationOp, 0),
|
||||
7: ('proposal', TezosProposalOp, 0),
|
||||
8: ('ballot', TezosBallotOp, 0),
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ async def change_page(page, page_count):
|
||||
else:
|
||||
s = await swipe
|
||||
if s == SWIPE_UP:
|
||||
return page + 1 # scroll down
|
||||
return min(page + 1, page_count - 1) # scroll down
|
||||
elif s == SWIPE_DOWN:
|
||||
return page - 1 # scroll up
|
||||
return max(page - 1, 0) # scroll up
|
||||
|
||||
|
||||
async def paginate(render_page, page_count, page=0, *args):
|
||||
|
@ -46,10 +46,11 @@ class TestTezosAddress(unittest.TestCase):
|
||||
[44 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 0],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 0 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 1, 0],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
[44 | HARDENED, 1729 | HARDENED, 1 | HARDENED, 1 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 9999000 | HARDENED],
|
||||
[44 | HARDENED, 60 | HARDENED, 0 | HARDENED, 0, 0],
|
||||
[1 | HARDENED, 1 | HARDENED, 1 | HARDENED],
|
||||
@ -58,6 +59,9 @@ class TestTezosAddress(unittest.TestCase):
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 3 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 9 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 0 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 3 | HARDENED],
|
||||
[44 | HARDENED, 1729 | HARDENED, 0 | HARDENED, 9 | HARDENED],
|
||||
]
|
||||
|
||||
for path in incorrect_paths:
|
||||
|
@ -4,9 +4,8 @@ from common import *
|
||||
from trezor.messages import TezosContractType
|
||||
from trezor.messages.TezosContractID import TezosContractID
|
||||
|
||||
from apps.tezos.helpers import base58_decode_check, base58_encode_check
|
||||
from apps.tezos.helpers import base58_decode_check, base58_encode_check, write_bool
|
||||
from apps.tezos.sign_tx import (
|
||||
_encode_bool,
|
||||
_encode_contract_id,
|
||||
_encode_data_with_bool_prefix,
|
||||
_encode_zarith,
|
||||
@ -35,11 +34,11 @@ class TestTezosEncoding(unittest.TestCase):
|
||||
|
||||
def test_tezos_encode_bool(self):
|
||||
w = bytearray()
|
||||
_encode_bool(w, True)
|
||||
write_bool(w, True)
|
||||
self.assertEqual(bytes(w), bytes([255]))
|
||||
|
||||
w = bytearray()
|
||||
_encode_bool(w, False)
|
||||
write_bool(w, False)
|
||||
self.assertEqual(bytes(w), bytes([0]))
|
||||
|
||||
def test_tezos_encode_contract_id(self):
|
||||
|
@ -14,6 +14,8 @@
|
||||
# You should have received a copy of the License along with this library.
|
||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from trezorlib import messages, tezos
|
||||
@ -23,6 +25,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 +197,152 @@ class TestMsgTezosSignTx(TrezorTest):
|
||||
assert (
|
||||
resp.operation_hash == "oocgc3hyKsGHPsw6WFWJpWT8jBwQLtebQAXF27KNisThkzoj635"
|
||||
)
|
||||
|
||||
def input_flow(self, num_pages):
|
||||
yield
|
||||
time.sleep(1)
|
||||
for _ in range(num_pages - 1):
|
||||
self.client.debug.swipe_down()
|
||||
time.sleep(1)
|
||||
self.client.debug.press_yes()
|
||||
|
||||
def test_tezos_sign_tx_proposal(self):
|
||||
self.setup_mnemonic_allallall()
|
||||
|
||||
self.client.set_input_flow(self.input_flow(num_pages=1))
|
||||
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()
|
||||
|
||||
self.client.set_input_flow(self.input_flow(num_pages=2))
|
||||
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