diff --git a/releases/Next-ChangeLog.md b/releases/Next-ChangeLog.md index c76ed518..914c41cd 100644 --- a/releases/Next-ChangeLog.md +++ b/releases/Next-ChangeLog.md @@ -4,6 +4,7 @@ This lists the new changes that have not yet been published in a normal release. # Shared Improvements - Both Mk4 and Q +- New Feature: Transaction output explorer - Enhancement: Stricter p2sh-p2wpkh validation - Enhancement: mention the need to remove old duress wallets before locking down temporary seed - Bugfix: Fix PSBTv2 `PSBT_GLOBAL_TX_MODIFIABLE` parsing diff --git a/shared/auth.py b/shared/auth.py index 73cfa018..c50d2d88 100644 --- a/shared/auth.py +++ b/shared/auth.py @@ -21,7 +21,7 @@ from psbt import psbtObject, FatalPSBTIssue, FraudulentChangeOutput from files import CardSlot from exceptions import HSMDenied from version import MAX_TXN_LEN -from charcodes import KEY_QR, KEY_NFC, KEY_ENTER, KEY_CANCEL +from charcodes import KEY_QR, KEY_NFC, KEY_ENTER, KEY_CANCEL, KEY_LEFT, KEY_RIGHT # Where in SPI flash/PSRAM the two PSBT files are (in and out) TXN_INPUT_OFFSET = 0 @@ -728,17 +728,27 @@ class ApproveTransaction(UserAuthorizedAction): self.result = await self.save_visualization(msg, (self.stxn_flags & STXN_SIGNED)) del self.psbt self.done() - return ux_clear_keys(True) dis.progress_bar_show(1) # finish the Validating... if not hsm_active: - msg.write("Press OK to approve and sign transaction.") + explore = self.psbt.num_outputs > 10 + msg.write("\nPress OK to approve and sign transaction.") + if explore: + msg.write(" Press (2) to explore txn.") if self.is_sd and CardSlot.both_inserted(): msg.write(" (B) to write to lower SD slot.") msg.write(" X to abort.") - ch = await ux_show_story(msg, title="OK TO SEND?", escape="b") + while True: + ch = await ux_show_story(msg, title="OK TO SEND?", escape="2b") + if ch == "2" and explore: + await self.txn_explorer() + continue + else: + msg.close() + del msg + break else: ch = await hsm_active.approve_transaction(self.psbt, self.psbt_sha, msg.getvalue()) dis.progress_bar_show(1) # finish the Validating... @@ -832,6 +842,51 @@ class ApproveTransaction(UserAuthorizedAction): continue break + async def txn_explorer(self): + from glob import dis + start = 0 + n = 10 + + def make_msg(start, n): + dis.fullscreen('Wait...') + rv = "" + end = min(start + n, self.psbt.num_outputs) + + for idx, out in self.psbt.output_iter(start, end): + outp = self.psbt.outputs[idx] + item = "Output %d%s:\n\n" % (idx, " (change)" if outp.is_change else "") + item += self.render_output(out) + item += "\n" + rv += item + + if self.psbt.num_outputs > n: + rv += "Press RIGHT to see next group, LEFT to go back. X to quit." + return rv + + msg = make_msg(start, n) + while True: + ch = await ux_show_story(msg, escape='79'+KEY_RIGHT+KEY_LEFT) + if ch == 'x': + del msg + return + elif (ch in KEY_LEFT+"7"): + # go backwards in explorer + if (start - n) < 0: + continue + else: + start -= n + elif (ch in KEY_RIGHT+"9"): + # go forwards + if (start + n) >= self.psbt.num_outputs: + continue + else: + start += n + else: + # nothing changed - do not recalc msg + continue + + msg = make_msg(start, n) + async def save_visualization(self, msg, sign_text=False): # write text into spi flash, maybe signing it as we go # - return length and checksum diff --git a/shared/psbt.py b/shared/psbt.py index 9116654a..b8be2fa8 100644 --- a/shared/psbt.py +++ b/shared/psbt.py @@ -1050,11 +1050,14 @@ class psbtObject(psbtProxy): raise FatalPSBTIssue("Duplicate key. Key for unknown value already provided in global namespace.") self.unknown[key] = val - def output_iter(self): + def output_iter(self, start=0, stop=None): # yield the txn's outputs: index, (CTxOut object) for each + if stop is None: + stop = self.num_outputs + total_out = 0 if self.is_v2: - for idx in range(self.num_outputs): + for idx in range(start, stop): out = self.outputs[idx] amount = unpack("