mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-18 05:28:40 +00:00
core/sign_tx: Reuse get_prevtx_output_value() in Decred.
This commit is contained in:
parent
2b74513e49
commit
60dbec95ac
@ -4,11 +4,12 @@ from micropython import const
|
|||||||
from trezor.crypto.hashlib import blake256
|
from trezor.crypto.hashlib import blake256
|
||||||
from trezor.messages import FailureType, InputScriptType
|
from trezor.messages import FailureType, InputScriptType
|
||||||
from trezor.messages.SignTx import SignTx
|
from trezor.messages.SignTx import SignTx
|
||||||
|
from trezor.messages.TransactionType import TransactionType
|
||||||
from trezor.messages.TxInputType import TxInputType
|
from trezor.messages.TxInputType import TxInputType
|
||||||
from trezor.messages.TxOutputBinType import TxOutputBinType
|
from trezor.messages.TxOutputBinType import TxOutputBinType
|
||||||
from trezor.messages.TxOutputType import TxOutputType
|
from trezor.messages.TxOutputType import TxOutputType
|
||||||
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
||||||
from trezor.utils import HashWriter
|
from trezor.utils import HashWriter, ensure
|
||||||
|
|
||||||
from apps.common import coininfo, seed
|
from apps.common import coininfo, seed
|
||||||
from apps.wallet.sign_tx import addresses, helpers, multisig, progress, scripts, writers
|
from apps.wallet.sign_tx import addresses, helpers, multisig, progress, scripts, writers
|
||||||
@ -20,6 +21,9 @@ DECRED_SERIALIZE_WITNESS_SIGNING = const(3 << 16)
|
|||||||
|
|
||||||
DECRED_SIGHASHALL = const(1)
|
DECRED_SIGHASHALL = const(1)
|
||||||
|
|
||||||
|
if False:
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class DecredPrefixHasher:
|
class DecredPrefixHasher:
|
||||||
"""
|
"""
|
||||||
@ -57,15 +61,19 @@ class Decred(Bitcoin):
|
|||||||
def initialize(
|
def initialize(
|
||||||
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
self, tx: SignTx, keychain: seed.Keychain, coin: coininfo.CoinInfo
|
||||||
) -> None:
|
) -> None:
|
||||||
|
ensure(coin.decred)
|
||||||
super().initialize(tx, keychain, coin)
|
super().initialize(tx, keychain, coin)
|
||||||
|
|
||||||
# This is required because the last serialized output obtained in
|
# This is required because the last serialized output obtained in
|
||||||
# `check_fee` will only be sent to the client in `sign_tx`
|
# phase 1 will only be sent to the client in phase 2
|
||||||
self.last_output_bytes = None # type: bytearray
|
self.last_output_bytes = None # type: bytearray
|
||||||
|
|
||||||
def init_hash143(self) -> None:
|
def init_hash143(self) -> None:
|
||||||
self.hash143 = DecredPrefixHasher(self.tx) # pseudo BIP-0143 prefix hashing
|
self.hash143 = DecredPrefixHasher(self.tx) # pseudo BIP-0143 prefix hashing
|
||||||
|
|
||||||
|
def create_hash_writer(self) -> HashWriter:
|
||||||
|
return HashWriter(blake256())
|
||||||
|
|
||||||
async def phase1(self) -> None:
|
async def phase1(self) -> None:
|
||||||
await super().phase1()
|
await super().phase1()
|
||||||
self.hash143.add_locktime_expiry(self.tx)
|
self.hash143.add_locktime_expiry(self.tx)
|
||||||
@ -75,7 +83,7 @@ class Decred(Bitcoin):
|
|||||||
w_txi = writers.empty_bytearray(8 if i == 0 else 0 + 9 + len(txi.prev_hash))
|
w_txi = writers.empty_bytearray(8 if i == 0 else 0 + 9 + len(txi.prev_hash))
|
||||||
if i == 0: # serializing first input => prepend headers
|
if i == 0: # serializing first input => prepend headers
|
||||||
self.write_sign_tx_header(w_txi, False)
|
self.write_sign_tx_header(w_txi, False)
|
||||||
writers.write_tx_input_decred(w_txi, txi)
|
self.write_tx_input(w_txi, txi)
|
||||||
self.tx_req.serialized = TxRequestSerializedType(None, None, w_txi)
|
self.tx_req.serialized = TxRequestSerializedType(None, None, w_txi)
|
||||||
|
|
||||||
async def phase1_confirm_output(
|
async def phase1_confirm_output(
|
||||||
@ -127,7 +135,7 @@ class Decred(Bitcoin):
|
|||||||
else:
|
else:
|
||||||
raise SigningError("Unsupported input script type")
|
raise SigningError("Unsupported input script type")
|
||||||
|
|
||||||
h_witness = HashWriter(blake256())
|
h_witness = self.create_hash_writer()
|
||||||
writers.write_uint32(
|
writers.write_uint32(
|
||||||
h_witness, self.tx.version | DECRED_SERIALIZE_WITNESS_SIGNING
|
h_witness, self.tx.version | DECRED_SERIALIZE_WITNESS_SIGNING
|
||||||
)
|
)
|
||||||
@ -143,7 +151,7 @@ class Decred(Bitcoin):
|
|||||||
h_witness, double=self.coin.sign_hash_double, reverse=False
|
h_witness, double=self.coin.sign_hash_double, reverse=False
|
||||||
)
|
)
|
||||||
|
|
||||||
h_sign = HashWriter(blake256())
|
h_sign = self.create_hash_writer()
|
||||||
writers.write_uint32(h_sign, DECRED_SIGHASHALL)
|
writers.write_uint32(h_sign, DECRED_SIGHASHALL)
|
||||||
writers.write_bytes_fixed(h_sign, prefix_hash, writers.TX_HASH_SIZE)
|
writers.write_bytes_fixed(h_sign, prefix_hash, writers.TX_HASH_SIZE)
|
||||||
writers.write_bytes_fixed(h_sign, witness_hash, writers.TX_HASH_SIZE)
|
writers.write_bytes_fixed(h_sign, witness_hash, writers.TX_HASH_SIZE)
|
||||||
@ -175,54 +183,30 @@ class Decred(Bitcoin):
|
|||||||
|
|
||||||
await helpers.request_tx_finish(self.tx_req)
|
await helpers.request_tx_finish(self.tx_req)
|
||||||
|
|
||||||
async def get_prevtx_output_value(self, prev_hash: bytes, prev_index: int) -> int:
|
def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None:
|
||||||
total_out = 0 # sum of output amounts
|
|
||||||
|
|
||||||
# STAGE_REQUEST_2_PREV_META
|
|
||||||
tx = await helpers.request_tx_meta(self.tx_req, self.coin, prev_hash)
|
|
||||||
|
|
||||||
if tx.outputs_cnt <= prev_index:
|
|
||||||
raise SigningError(
|
|
||||||
FailureType.ProcessError, "Not enough outputs in previous transaction."
|
|
||||||
)
|
|
||||||
|
|
||||||
txh = HashWriter(blake256())
|
|
||||||
writers.write_uint32(txh, tx.version | DECRED_SERIALIZE_NO_WITNESS)
|
|
||||||
writers.write_varint(txh, tx.inputs_cnt)
|
|
||||||
|
|
||||||
for i in range(tx.inputs_cnt):
|
|
||||||
# STAGE_REQUEST_2_PREV_INPUT
|
|
||||||
txi = await helpers.request_tx_input(self.tx_req, i, self.coin, prev_hash)
|
|
||||||
writers.write_tx_input_decred(txh, txi)
|
|
||||||
|
|
||||||
writers.write_varint(txh, tx.outputs_cnt)
|
|
||||||
|
|
||||||
for o in range(tx.outputs_cnt):
|
|
||||||
# STAGE_REQUEST_2_PREV_OUTPUT
|
|
||||||
txo_bin = await helpers.request_tx_output(
|
|
||||||
self.tx_req, o, self.coin, prev_hash
|
|
||||||
)
|
|
||||||
writers.write_tx_output(txh, txo_bin)
|
|
||||||
if o == prev_index:
|
|
||||||
total_out += txo_bin.amount
|
|
||||||
if (
|
|
||||||
txo_bin.decred_script_version is not None
|
|
||||||
and txo_bin.decred_script_version != 0
|
|
||||||
):
|
|
||||||
raise SigningError(
|
|
||||||
FailureType.ProcessError,
|
|
||||||
"Cannot use utxo that has script_version != 0",
|
|
||||||
)
|
|
||||||
|
|
||||||
writers.write_uint32(txh, tx.lock_time)
|
|
||||||
writers.write_uint32(txh, tx.expiry)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
writers.get_tx_hash(txh, double=self.coin.sign_hash_double, reverse=True)
|
txo_bin.decred_script_version is not None
|
||||||
!= prev_hash
|
and txo_bin.decred_script_version != 0
|
||||||
):
|
):
|
||||||
raise SigningError(
|
raise SigningError(
|
||||||
FailureType.ProcessError, "Encountered invalid prev_hash"
|
FailureType.ProcessError,
|
||||||
|
"Cannot use utxo that has script_version != 0",
|
||||||
)
|
)
|
||||||
|
|
||||||
return total_out
|
def write_tx_input(self, w: writers.Writer, i: TxInputType) -> None:
|
||||||
|
writers.write_tx_input_decred(w, i)
|
||||||
|
|
||||||
|
def write_sign_tx_header(self, w: writers.Writer, has_segwit: bool) -> None:
|
||||||
|
writers.write_uint32(w, self.tx.version) # nVersion
|
||||||
|
writers.write_varint(w, self.tx.inputs_count)
|
||||||
|
|
||||||
|
def write_tx_header(
|
||||||
|
self, w: writers.Writer, tx: Union[SignTx, TransactionType], has_segwit: bool
|
||||||
|
) -> None:
|
||||||
|
writers.write_uint32(w, tx.version | DECRED_SERIALIZE_NO_WITNESS)
|
||||||
|
|
||||||
|
async def write_prev_tx_footer(
|
||||||
|
self, w: writers.Writer, tx: TransactionType, prev_hash: bytes
|
||||||
|
) -> None:
|
||||||
|
writers.write_uint32(w, tx.lock_time)
|
||||||
|
writers.write_uint32(w, tx.expiry)
|
||||||
|
@ -98,13 +98,16 @@ class Bitcoin:
|
|||||||
# h_first is used to make sure the inputs and outputs streamed in Phase 1
|
# h_first is used to make sure the inputs and outputs streamed in Phase 1
|
||||||
# are the same as in Phase 2 when signing legacy inputs. it is thus not required to fully hash the
|
# are the same as in Phase 2 when signing legacy inputs. it is thus not required to fully hash the
|
||||||
# tx, as the SignTx info is streamed only once
|
# tx, as the SignTx info is streamed only once
|
||||||
self.h_first = utils.HashWriter(sha256()) # not a real tx hash
|
self.h_first = self.create_hash_writer() # not a real tx hash
|
||||||
|
|
||||||
self.init_hash143()
|
self.init_hash143()
|
||||||
|
|
||||||
def init_hash143(self) -> None:
|
def init_hash143(self) -> None:
|
||||||
self.hash143 = segwit_bip143.Bip143() # BIP-0143 transaction hashing
|
self.hash143 = segwit_bip143.Bip143() # BIP-0143 transaction hashing
|
||||||
|
|
||||||
|
def create_hash_writer(self) -> utils.HashWriter:
|
||||||
|
return utils.HashWriter(sha256())
|
||||||
|
|
||||||
async def phase1(self) -> None:
|
async def phase1(self) -> None:
|
||||||
weight = tx_weight.TxWeightCalculator(
|
weight = tx_weight.TxWeightCalculator(
|
||||||
self.tx.inputs_count, self.tx.outputs_count
|
self.tx.inputs_count, self.tx.outputs_count
|
||||||
@ -267,7 +270,7 @@ class Bitcoin:
|
|||||||
)
|
)
|
||||||
if i_sign == 0: # serializing first input => prepend headers
|
if i_sign == 0: # serializing first input => prepend headers
|
||||||
self.write_sign_tx_header(w_txi, True)
|
self.write_sign_tx_header(w_txi, True)
|
||||||
writers.write_tx_input(w_txi, txi_sign)
|
self.write_tx_input(w_txi, txi_sign)
|
||||||
self.tx_req.serialized = TxRequestSerializedType(serialized_tx=w_txi)
|
self.tx_req.serialized = TxRequestSerializedType(serialized_tx=w_txi)
|
||||||
|
|
||||||
async def phase2_sign_segwit_input(self, i: int) -> Tuple[bytearray, bytes]:
|
async def phase2_sign_segwit_input(self, i: int) -> Tuple[bytearray, bytes]:
|
||||||
@ -308,9 +311,9 @@ class Bitcoin:
|
|||||||
|
|
||||||
async def phase2_sign_nonsegwit_input(self, i_sign: int) -> None:
|
async def phase2_sign_nonsegwit_input(self, i_sign: int) -> None:
|
||||||
# hash of what we are signing with this input
|
# hash of what we are signing with this input
|
||||||
h_sign = utils.HashWriter(sha256())
|
h_sign = self.create_hash_writer()
|
||||||
# same as h_first, checked before signing the digest
|
# same as h_first, checked before signing the digest
|
||||||
h_second = utils.HashWriter(sha256())
|
h_second = self.create_hash_writer()
|
||||||
|
|
||||||
self.write_sign_tx_header(h_sign, has_segwit=False)
|
self.write_sign_tx_header(h_sign, has_segwit=False)
|
||||||
|
|
||||||
@ -341,7 +344,7 @@ class Bitcoin:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
txi.script_sig = bytes()
|
txi.script_sig = bytes()
|
||||||
writers.write_tx_input(h_sign, txi)
|
self.write_tx_input(h_sign, txi)
|
||||||
|
|
||||||
writers.write_varint(h_sign, self.tx.outputs_count)
|
writers.write_varint(h_sign, self.tx.outputs_count)
|
||||||
|
|
||||||
@ -382,7 +385,7 @@ class Bitcoin:
|
|||||||
)
|
)
|
||||||
if i_sign == 0: # serializing first input => prepend headers
|
if i_sign == 0: # serializing first input => prepend headers
|
||||||
self.write_sign_tx_header(w_txi_sign, True in self.segwit.values())
|
self.write_sign_tx_header(w_txi_sign, True in self.segwit.values())
|
||||||
writers.write_tx_input(w_txi_sign, txi_sign)
|
self.write_tx_input(w_txi_sign, txi_sign)
|
||||||
self.tx_req.serialized = TxRequestSerializedType(i_sign, signature, w_txi_sign)
|
self.tx_req.serialized = TxRequestSerializedType(i_sign, signature, w_txi_sign)
|
||||||
|
|
||||||
async def phase2_serialize_output(self, i: int) -> bytearray:
|
async def phase2_serialize_output(self, i: int) -> bytearray:
|
||||||
@ -410,7 +413,7 @@ class Bitcoin:
|
|||||||
FailureType.ProcessError, "Not enough outputs in previous transaction."
|
FailureType.ProcessError, "Not enough outputs in previous transaction."
|
||||||
)
|
)
|
||||||
|
|
||||||
txh = utils.HashWriter(sha256())
|
txh = self.create_hash_writer()
|
||||||
|
|
||||||
# TODO set has_segwit correctly
|
# TODO set has_segwit correctly
|
||||||
self.write_tx_header(txh, tx, has_segwit=False)
|
self.write_tx_header(txh, tx, has_segwit=False)
|
||||||
@ -419,7 +422,7 @@ class Bitcoin:
|
|||||||
for i in range(tx.inputs_cnt):
|
for i in range(tx.inputs_cnt):
|
||||||
# STAGE_REQUEST_2_PREV_INPUT
|
# STAGE_REQUEST_2_PREV_INPUT
|
||||||
txi = await helpers.request_tx_input(self.tx_req, i, self.coin, prev_hash)
|
txi = await helpers.request_tx_input(self.tx_req, i, self.coin, prev_hash)
|
||||||
writers.write_tx_input(txh, txi)
|
self.write_tx_input(txh, txi)
|
||||||
|
|
||||||
writers.write_varint(txh, tx.outputs_cnt)
|
writers.write_varint(txh, tx.outputs_cnt)
|
||||||
|
|
||||||
@ -431,6 +434,7 @@ class Bitcoin:
|
|||||||
writers.write_tx_output(txh, txo_bin)
|
writers.write_tx_output(txh, txo_bin)
|
||||||
if o == prev_index:
|
if o == prev_index:
|
||||||
amount_out = txo_bin.amount
|
amount_out = txo_bin.amount
|
||||||
|
self.check_prevtx_output(txo_bin)
|
||||||
|
|
||||||
await self.write_prev_tx_footer(txh, tx, prev_hash)
|
await self.write_prev_tx_footer(txh, tx, prev_hash)
|
||||||
|
|
||||||
@ -444,6 +448,9 @@ class Bitcoin:
|
|||||||
|
|
||||||
return amount_out
|
return amount_out
|
||||||
|
|
||||||
|
def check_prevtx_output(self, txo_bin: TxOutputBinType) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
# TX Helpers
|
# TX Helpers
|
||||||
# ===
|
# ===
|
||||||
|
|
||||||
@ -451,6 +458,9 @@ class Bitcoin:
|
|||||||
SIGHASH_ALL = const(0x01)
|
SIGHASH_ALL = const(0x01)
|
||||||
return SIGHASH_ALL
|
return SIGHASH_ALL
|
||||||
|
|
||||||
|
def write_tx_input(self, w: writers.Writer, i: TxInputType) -> None:
|
||||||
|
writers.write_tx_input(w, i)
|
||||||
|
|
||||||
def write_sign_tx_header(self, w: writers.Writer, has_segwit: bool) -> None:
|
def write_sign_tx_header(self, w: writers.Writer, has_segwit: bool) -> None:
|
||||||
self.write_tx_header(w, self.tx, has_segwit)
|
self.write_tx_header(w, self.tx, has_segwit)
|
||||||
writers.write_varint(w, self.tx.inputs_count)
|
writers.write_varint(w, self.tx.inputs_count)
|
||||||
@ -551,7 +561,7 @@ class Bitcoin:
|
|||||||
if i.multisig:
|
if i.multisig:
|
||||||
# p2wsh in p2sh
|
# p2wsh in p2sh
|
||||||
pubkeys = multisig.multisig_get_pubkeys(i.multisig)
|
pubkeys = multisig.multisig_get_pubkeys(i.multisig)
|
||||||
witness_script_hasher = utils.HashWriter(sha256())
|
witness_script_hasher = self.create_hash_writer()
|
||||||
scripts.write_output_script_multisig(
|
scripts.write_output_script_multisig(
|
||||||
witness_script_hasher, pubkeys, i.multisig.m
|
witness_script_hasher, pubkeys, i.multisig.m
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user