mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-19 21:08:07 +00:00
signtx: add UI similar to trezor1
This commit is contained in:
parent
710cb09663
commit
44f6f21186
@ -13,7 +13,7 @@ from trezor.messages.TxRequest import TxRequest
|
|||||||
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXMETA, TXFINISHED
|
from trezor.messages.RequestType import TXINPUT, TXOUTPUT, TXMETA, TXFINISHED
|
||||||
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
||||||
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
|
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
|
||||||
from trezor.messages import OutputScriptType, InputScriptType
|
from trezor.messages import OutputScriptType, InputScriptType, FailureType
|
||||||
|
|
||||||
|
|
||||||
# Machine instructions
|
# Machine instructions
|
||||||
@ -26,23 +26,25 @@ class SigningError(ValueError):
|
|||||||
|
|
||||||
class UiConfirmOutput:
|
class UiConfirmOutput:
|
||||||
|
|
||||||
def __init__(self, output: TxOutputType):
|
def __init__(self, output: TxOutputType, coin: CoinType):
|
||||||
self.output = output
|
self.output = output
|
||||||
|
self.coin = coin
|
||||||
|
|
||||||
|
|
||||||
class UiConfirmTotal:
|
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.total_out = total_out
|
||||||
self.fee = fee
|
self.fee = fee
|
||||||
|
self.coin = coin
|
||||||
|
|
||||||
|
|
||||||
def confirm_output(output: TxOutputType):
|
def confirm_output(output: TxOutputType, coin: CoinType):
|
||||||
yield UiConfirmOutput(output)
|
return (yield UiConfirmOutput(output, coin))
|
||||||
|
|
||||||
|
|
||||||
def confirm_total(total_out: int, fee: int):
|
def confirm_total(total_out: int, fee: int, coin: CoinType):
|
||||||
yield UiConfirmTotal(total_out, fee)
|
return (yield UiConfirmTotal(total_out, fee, coin))
|
||||||
|
|
||||||
|
|
||||||
def request_tx_meta(tx_req: TxRequest, tx_hash: bytes=None):
|
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)
|
txo = await request_tx_output(tx_req, o)
|
||||||
if output_is_change(txo):
|
if output_is_change(txo):
|
||||||
if change_out != 0:
|
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
|
change_out = txo.amount
|
||||||
txo_bin.amount = txo.amount
|
txo_bin.amount = txo.amount
|
||||||
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
|
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
|
||||||
write_tx_output(h_first, txo_bin)
|
write_tx_output(h_first, txo_bin)
|
||||||
total_out += txo_bin.amount
|
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
|
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
|
# Phase 2
|
||||||
# - sign inputs
|
# - sign inputs
|
||||||
@ -187,7 +196,8 @@ async def sign_tx(tx: SignTx, root):
|
|||||||
|
|
||||||
# check the control digests
|
# check the control digests
|
||||||
if get_tx_hash(h_first, False) != get_tx_hash(h_second, False):
|
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
|
# compute the signature from the tx digest
|
||||||
signature = ecdsa_sign(key_sign, get_tx_hash(h_sign, True))
|
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)
|
write_uint32(txh, tx_lock_time)
|
||||||
|
|
||||||
if get_tx_hash(txh, True, True) != prev_hash:
|
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
|
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)
|
ra = output_paytoaddress_extract_raw_address(o, coin, root)
|
||||||
return script_paytoaddress_new(ra[1:])
|
return script_paytoaddress_new(ra[1:])
|
||||||
else:
|
else:
|
||||||
raise SigningError('Invalid output script type')
|
raise SigningError(FailureType.SyntaxError,
|
||||||
|
'Invalid output script type')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def output_paytoaddress_extract_raw_address(o: TxOutputType, coin: CoinType, root) -> bytes:
|
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: dont encode/decode more then necessary
|
||||||
# TODO: detect correct address type
|
# TODO: detect correct address type
|
||||||
if o_address_n is not None:
|
address_n = getattr(o, 'address_n', None)
|
||||||
n = node_derive(root, o_address_n)
|
if address_n is not None:
|
||||||
raw_address = base58.decode_check(n.address(coin.address_type))
|
node = node_derive(root, address_n)
|
||||||
elif o_address:
|
address = node.address(coin.address_type)
|
||||||
raw_address = base58.decode_check(o_address)
|
return base58.decode_check(address)
|
||||||
if raw_address[0] != coin.address_type:
|
address = getattr(o, 'address', None)
|
||||||
raise SigningError('Invalid address type')
|
if address:
|
||||||
else:
|
raw = base58.decode_check(address)
|
||||||
raise SigningError('Missing address')
|
if raw[0] != coin.address_type:
|
||||||
return raw_address
|
raise SigningError(FailureType.SyntaxError,
|
||||||
|
'Invalid address type')
|
||||||
|
return raw
|
||||||
|
raise SigningError(FailureType.SyntaxError,
|
||||||
|
'Missing address')
|
||||||
|
|
||||||
|
|
||||||
def output_is_change(output: TxOutputType):
|
def output_is_change(o: TxOutputType):
|
||||||
address_n = getattr(output, 'address_n', None)
|
address_n = getattr(o, 'address_n', None)
|
||||||
return bool(address_n)
|
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:
|
if i_script_type == InputScriptType.SPENDADDRESS:
|
||||||
return script_paytoaddress_new(ecdsa_hash_pubkey(pubkey))
|
return script_paytoaddress_new(ecdsa_hash_pubkey(pubkey))
|
||||||
else:
|
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:
|
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:
|
if i_script_type == InputScriptType.SPENDADDRESS:
|
||||||
return script_spendaddress_new(pubkey, signature)
|
return script_spendaddress_new(pubkey, signature)
|
||||||
else:
|
else:
|
||||||
raise SigningError('Unknown input script type')
|
raise SigningError(FailureType.SyntaxError,
|
||||||
|
'Unknown input script type')
|
||||||
|
|
||||||
|
|
||||||
def node_derive(root, address_n: list):
|
def node_derive(root, address_n: list):
|
||||||
|
@ -2,12 +2,34 @@ from trezor.utils import unimport
|
|||||||
from trezor import wire
|
from trezor import wire
|
||||||
|
|
||||||
|
|
||||||
async def confirm_output(output):
|
def format_amount(amount, coin):
|
||||||
return True
|
return '%s %s' % (amount / 1e8, coin.coin_shortcut)
|
||||||
|
|
||||||
|
|
||||||
async def confirm_total(total_out, fee):
|
async def confirm_output(session_id, output, coin):
|
||||||
return True
|
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
|
@unimport
|
||||||
@ -33,9 +55,10 @@ async def layout_sign_tx(message, session_id):
|
|||||||
break
|
break
|
||||||
res = await wire.reply_message(session_id, req, TxAck)
|
res = await wire.reply_message(session_id, req, TxAck)
|
||||||
elif isinstance(req, signtx.UiConfirmOutput):
|
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):
|
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:
|
else:
|
||||||
|
print(req)
|
||||||
raise ValueError('Invalid signing instruction')
|
raise ValueError('Invalid signing instruction')
|
||||||
return req
|
return req
|
||||||
|
Loading…
Reference in New Issue
Block a user