mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-03 03:50:58 +00:00
core/bitcoin: Support multiple change-outputs.
This commit is contained in:
parent
91da49266c
commit
eb28998f98
@ -14,6 +14,7 @@ _Most likely to be released on July 1st._
|
||||
- Dedicated `initialized` field in storage.
|
||||
- Support EXTERNAL transaction inputs with a SLIP-0019 proof of ownership. [#1052]
|
||||
- Support pre-signed EXTERNAL transaction inputs.
|
||||
- Support multiple change-outputs. [#1098]
|
||||
|
||||
### Changed
|
||||
- `Features.pin_cached` renamed to `unlocked`.
|
||||
@ -168,3 +169,4 @@ Version 2.0.5 [Mar 2018]
|
||||
[#1056]: https://github.com/trezor/trezor-firmware/issues/1056
|
||||
[#1067]: https://github.com/trezor/trezor-firmware/issues/1067
|
||||
[#1074]: https://github.com/trezor/trezor-firmware/issues/1074
|
||||
[#1098]: https://github.com/trezor/trezor-firmware/issues/1098
|
||||
|
@ -67,6 +67,13 @@ async def sign_tx(
|
||||
res = await layout.confirm_feeoverthreshold(ctx, req.fee, req.coin)
|
||||
utils.unimport_end(mods)
|
||||
progress.report_init()
|
||||
elif isinstance(req, helpers.UiConfirmChangeCountOverThreshold):
|
||||
mods = utils.unimport_begin()
|
||||
res = await layout.confirm_change_count_over_threshold(
|
||||
ctx, req.change_count
|
||||
)
|
||||
utils.unimport_end(mods)
|
||||
progress.report_init()
|
||||
elif isinstance(req, helpers.UiConfirmNonDefaultLocktime):
|
||||
mods = utils.unimport_begin()
|
||||
res = await layout.confirm_nondefault_locktime(ctx, req.lock_time)
|
||||
|
@ -38,6 +38,9 @@ _BIP32_MAX_LAST_ELEMENT = const(1000000)
|
||||
# the number of bytes to preallocate for serialized transaction chunks
|
||||
_MAX_SERIALIZED_CHUNK_SIZE = const(2048)
|
||||
|
||||
# the maximum number of change-outputs allowed without user confirmation
|
||||
_MAX_SILENT_CHANGE_COUNT = const(2)
|
||||
|
||||
|
||||
class Bitcoin:
|
||||
async def signer(self) -> None:
|
||||
@ -92,6 +95,7 @@ class Bitcoin:
|
||||
self.external_in = 0 # sum of external input amounts
|
||||
self.total_out = 0 # sum of output amounts
|
||||
self.change_out = 0 # change output amount
|
||||
self.change_count = 0 # the number of change-outputs
|
||||
self.weight = tx_weight.TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
||||
|
||||
# transaction and signature serialization
|
||||
@ -154,6 +158,8 @@ class Bitcoin:
|
||||
# fee > (coin.maxfee per byte * tx size)
|
||||
if fee > (self.coin.maxfee_kb / 1000) * (self.weight.get_total() / 4):
|
||||
await helpers.confirm_feeoverthreshold(fee, self.coin)
|
||||
if self.change_count > _MAX_SILENT_CHANGE_COUNT:
|
||||
await helpers.confirm_change_count_over_threshold(self.change_count)
|
||||
if self.tx.lock_time > 0:
|
||||
await helpers.confirm_nondefault_locktime(self.tx.lock_time)
|
||||
if not self.external:
|
||||
@ -268,9 +274,10 @@ class Bitcoin:
|
||||
self.external_in += txi.amount
|
||||
|
||||
async def confirm_output(self, txo: TxOutputType, script_pubkey: bytes) -> None:
|
||||
if self.change_out == 0 and self.output_is_change(txo):
|
||||
if self.output_is_change(txo):
|
||||
# output is change and does not need confirmation
|
||||
self.change_out = txo.amount
|
||||
self.change_out += txo.amount
|
||||
self.change_count += 1
|
||||
else:
|
||||
await helpers.confirm_output(txo, self.coin)
|
||||
|
||||
|
@ -63,6 +63,13 @@ class UiConfirmFeeOverThreshold:
|
||||
__eq__ = utils.obj_eq
|
||||
|
||||
|
||||
class UiConfirmChangeCountOverThreshold:
|
||||
def __init__(self, change_count: int):
|
||||
self.change_count = change_count
|
||||
|
||||
__eq__ = utils.obj_eq
|
||||
|
||||
|
||||
class UiConfirmForeignAddress:
|
||||
def __init__(self, address_n: list):
|
||||
self.address_n = address_n
|
||||
@ -93,6 +100,10 @@ def confirm_feeoverthreshold(fee: int, coin: CoinInfo) -> Awaitable[Any]: # typ
|
||||
return (yield UiConfirmFeeOverThreshold(fee, coin))
|
||||
|
||||
|
||||
def confirm_change_count_over_threshold(change_count: int) -> Awaitable[Any]: # type: ignore
|
||||
return (yield UiConfirmChangeCountOverThreshold(change_count))
|
||||
|
||||
|
||||
def confirm_foreign_address(address_n: list) -> Awaitable[Any]: # type: ignore
|
||||
return (yield UiConfirmForeignAddress(address_n))
|
||||
|
||||
|
@ -99,6 +99,20 @@ async def confirm_feeoverthreshold(
|
||||
await require_confirm(ctx, text, ButtonRequestType.FeeOverThreshold)
|
||||
|
||||
|
||||
async def confirm_change_count_over_threshold(
|
||||
ctx: wire.Context, change_count: int
|
||||
) -> None:
|
||||
from trezor.ui.text import Text
|
||||
from apps.common.confirm import require_confirm
|
||||
|
||||
text = Text("Warning", ui.ICON_SEND, ui.GREEN)
|
||||
text.normal("There are {}".format(change_count))
|
||||
text.normal("change-outputs.")
|
||||
text.br_half()
|
||||
text.normal("Continue?")
|
||||
await require_confirm(ctx, text, ButtonRequestType.SignTx)
|
||||
|
||||
|
||||
async def confirm_nondefault_locktime(ctx: wire.Context, lock_time: int) -> None:
|
||||
from trezor.ui.text import Text
|
||||
from apps.common.confirm import require_confirm
|
||||
|
Loading…
Reference in New Issue
Block a user