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

signtx: add UI similar to trezor1

This commit is contained in:
Jan Pochyla 2016-11-11 14:13:04 +01:00
parent 710cb09663
commit 44f6f21186
2 changed files with 74 additions and 35 deletions

View File

@ -13,7 +13,7 @@ from trezor.messages.TxRequest import TxRequest
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXMETA, TXFINISHED
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
from trezor.messages import OutputScriptType, InputScriptType
from trezor.messages import OutputScriptType, InputScriptType, FailureType
# Machine instructions
@ -26,23 +26,25 @@ class SigningError(ValueError):
class UiConfirmOutput:
def __init__(self, output: TxOutputType):
def __init__(self, output: TxOutputType, coin: CoinType):
self.output = output
self.coin = coin
class UiConfirmTotal:
def __init__(self, total_out: int, fee: int):
def __init__(self, total_out: int, fee: int, coin: CoinType):
self.total_out = total_out
self.fee = fee
self.coin = coin
def confirm_output(output: TxOutputType):
yield UiConfirmOutput(output)
def confirm_output(output: TxOutputType, coin: CoinType):
return (yield UiConfirmOutput(output, coin))
def confirm_total(total_out: int, fee: int):
yield UiConfirmTotal(total_out, fee)
def confirm_total(total_out: int, fee: int, coin: CoinType):
return (yield UiConfirmTotal(total_out, fee, coin))
def request_tx_meta(tx_req: TxRequest, tx_hash: bytes=None):
@ -125,16 +127,23 @@ async def sign_tx(tx: SignTx, root):
txo = await request_tx_output(tx_req, o)
if output_is_change(txo):
if change_out != 0:
raise SigningError('Only one change output is valid')
raise SigningError(FailureType.Other,
'Only one change output is valid')
change_out = txo.amount
txo_bin.amount = txo.amount
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
write_tx_output(h_first, txo_bin)
total_out += txo_bin.amount
await confirm_output(txo)
if not output_is_change(txo) and not await confirm_output(txo, coin):
raise SigningError(FailureType.ActionCancelled,
'Output cancelled')
fee = total_in - total_out
await confirm_total(total_out, fee)
if not await confirm_total(total_out, fee, coin):
raise SigningError(FailureType.ActionCancelled,
'Total cancelled')
# Phase 2
# - sign inputs
@ -187,7 +196,8 @@ async def sign_tx(tx: SignTx, root):
# check the control digests
if get_tx_hash(h_first, False) != get_tx_hash(h_second, False):
raise SigningError('Transaction has changed during signing')
raise SigningError(FailureType.Other,
'Transaction has changed during signing')
# compute the signature from the tx digest
signature = ecdsa_sign(key_sign, get_tx_hash(h_sign, True))
@ -262,7 +272,8 @@ async def get_prevtx_output_value(tx_req: TxRequest, prev_hash: bytes, prev_inde
write_uint32(txh, tx_lock_time)
if get_tx_hash(txh, True, True) != prev_hash:
raise SigningError('Encountered invalid prev_hash')
raise SigningError(FailureType.Other,
'Encountered invalid prev_hash')
return total_out
@ -285,29 +296,32 @@ def output_derive_script(o: TxOutputType, coin: CoinType, root) -> bytes:
ra = output_paytoaddress_extract_raw_address(o, coin, root)
return script_paytoaddress_new(ra[1:])
else:
raise SigningError('Invalid output script type')
raise SigningError(FailureType.SyntaxError,
'Invalid output script type')
return
def output_paytoaddress_extract_raw_address(o: TxOutputType, coin: CoinType, root) -> bytes:
o_address_n = getattr(o, 'address_n', None)
o_address = getattr(o, 'address', None)
# TODO: dont encode/decode more then necessary
# TODO: detect correct address type
if o_address_n is not None:
n = node_derive(root, o_address_n)
raw_address = base58.decode_check(n.address(coin.address_type))
elif o_address:
raw_address = base58.decode_check(o_address)
if raw_address[0] != coin.address_type:
raise SigningError('Invalid address type')
else:
raise SigningError('Missing address')
return raw_address
address_n = getattr(o, 'address_n', None)
if address_n is not None:
node = node_derive(root, address_n)
address = node.address(coin.address_type)
return base58.decode_check(address)
address = getattr(o, 'address', None)
if address:
raw = base58.decode_check(address)
if raw[0] != coin.address_type:
raise SigningError(FailureType.SyntaxError,
'Invalid address type')
return raw
raise SigningError(FailureType.SyntaxError,
'Missing address')
def output_is_change(output: TxOutputType):
address_n = getattr(output, 'address_n', None)
def output_is_change(o: TxOutputType):
address_n = getattr(o, 'address_n', None)
return bool(address_n)
@ -320,7 +334,8 @@ def input_derive_script_pre_sign(i: TxInputType, pubkey: bytes) -> bytes:
if i_script_type == InputScriptType.SPENDADDRESS:
return script_paytoaddress_new(ecdsa_hash_pubkey(pubkey))
else:
raise SigningError('Unknown input script type')
raise SigningError(FailureType.SyntaxError,
'Unknown input script type')
def input_derive_script_post_sign(i: TxInputType, pubkey: bytes, signature: bytes) -> bytes:
@ -328,7 +343,8 @@ def input_derive_script_post_sign(i: TxInputType, pubkey: bytes, signature: byte
if i_script_type == InputScriptType.SPENDADDRESS:
return script_spendaddress_new(pubkey, signature)
else:
raise SigningError('Unknown input script type')
raise SigningError(FailureType.SyntaxError,
'Unknown input script type')
def node_derive(root, address_n: list):

View File

@ -2,12 +2,34 @@ from trezor.utils import unimport
from trezor import wire
async def confirm_output(output):
return True
def format_amount(amount, coin):
return '%s %s' % (amount / 1e8, coin.coin_shortcut)
async def confirm_total(total_out, fee):
return True
async def confirm_output(session_id, output, coin):
from trezor import ui
from trezor.ui.text import Text
from trezor.messages.ButtonRequestType import ConfirmOutput
from ..common.confirm import confirm
content = Text('Confirm output', ui.ICON_RESET,
ui.BOLD, format_amount(output.amount, coin),
ui.NORMAL, 'to',
ui.MONO, output.address[0:17],
ui.MONO, output.address[17:])
return await confirm(session_id, content, ConfirmOutput)
async def confirm_total(session_id, total_out, fee, coin):
from trezor import ui
from trezor.ui.text import Text
from trezor.messages.ButtonRequestType import SignTx
from ..common.confirm import confirm
content = Text('Confirm transaction', ui.ICON_RESET,
'Sending: %s' % format_amount(total_out, coin),
'Fee: %s' % format_amount(fee, coin))
return await confirm(session_id, content, SignTx)
@unimport
@ -33,9 +55,10 @@ async def layout_sign_tx(message, session_id):
break
res = await wire.reply_message(session_id, req, TxAck)
elif isinstance(req, signtx.UiConfirmOutput):
res = await confirm_output(req.output)
res = await confirm_output(session_id, req.output, req.coin)
elif isinstance(req, signtx.UiConfirmTotal):
res = await confirm_total(req.total_out, req.fee)
res = await confirm_total(session_id, req.total_out, req.fee, req.coin)
else:
print(req)
raise ValueError('Invalid signing instruction')
return req