What changed, and why it matters
This commit adds a small user-interface convenience to the COLDCARD transaction explorer: users can now press the '2' key to jump directly to a specific input or output index, instead of paging through items one screen at a time. It also fixes a minor edge case where pressing the left/back key from the first page could produce a negative starting index. There is no security-relevant change here.
No security action needed. Treat as a normal feature/UX improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch extends the TXExplorer class in shared/auth.py. It imports ux_enter_number, adds a ‘(2) to go to index’ hint, includes ‘2’ in the accepted escape characters, and implements a handler that prompts the user for a start index, clamps it to the valid range, and redisplays the explorer. It also hardens the KEY_LEFT/‘7’ backward navigation by preventing start from going below zero. A new test in testing/test_sign.py exercises the new ‘goto index’ feature for both inputs and outputs, including boundary behavior.
Changed components
shared/auth.py (TXExplorer user interface)testing/test_sign.py (new regression test)Inspect captured patch +77 / −8
diff --git a/shared/auth.py b/shared/auth.py
index 91b96e7..f91ad4f 100644
--- a/shared/auth.py
+++ b/shared/auth.py
@@ -14,7 +14,7 @@ from sffile import SFFile
from menu import MenuSystem, MenuItem
from serializations import ser_uint256, SIGHASH_ALL
from ux import ux_show_story, abort_and_goto, ux_dramatic_pause, ux_clear_keys, ux_confirm
-from ux import show_qr_code, OK, X, abort_and_push, AbortInteraction, the_ux
+from ux import show_qr_code, OK, X, abort_and_push, AbortInteraction, the_ux, ux_enter_number
from usb import CCBusyError
from utils import (HexWriter, xfp2str, problem_file_line, cleanup_deriv_path, B2A,
show_single_address, keypath_to_str, seconds2human_readable)
@@ -1546,6 +1546,8 @@ class TXExplorer:
if offset:
rv += ', LEFT to go back'
+ rv += ", (2) to go to index"
+
if not version.has_qwerty:
# Q has hint key
rv += ", (4) to show QR code"
@@ -1563,7 +1565,7 @@ class TXExplorer:
msg, addrs, change, end = self.make_ux_msg(start, self.n)
while True:
- ch = await ux_show_story(msg, title=self.title, escape='479'+KEY_RIGHT+KEY_LEFT+KEY_QR,
+ ch = await ux_show_story(msg, title=self.title, escape='2479'+KEY_RIGHT+KEY_LEFT+KEY_QR,
hint_icons=KEY_QR)
if ch == 'x':
del msg
@@ -1577,17 +1579,20 @@ class TXExplorer:
qr_msgs=self.qr_msgs, no_index=bool(self.qr_msgs))
continue
elif ch in (KEY_LEFT+"7"):
- if (start - self.n) < 0:
- continue
- else:
- # go backwards in explorer
- start -= self.n
+ if not start: continue # 0
+ start = max(start - self.n, 0)
+
elif ch in (KEY_RIGHT+"9"):
if (start + self.n) >= self.max_items:
continue
else:
# go forwards
start += self.n
+ elif ch == "2":
+ max_v = self.max_items - 1
+ res = await ux_enter_number("Start Idx (0-%d):" % max_v, max_value=max_v)
+ if res is None: continue
+ start = res
else:
# nothing changed - do not recalc msg
continue
diff --git a/testing/test_sign.py b/testing/test_sign.py
index 0365b71..54cbc47 100644
--- a/testing/test_sign.py
+++ b/testing/test_sign.py
@@ -20,7 +20,7 @@ from constants import ADDR_STYLES, ADDR_STYLES_SINGLE, SIGHASH_MAP, simulator_fi
from txn import *
from ctransaction import CTransaction, CTxOut, CTxIn, COutPoint
from ckcc_protocol.constants import STXN_VISUALIZE, STXN_SIGNED
-from charcodes import KEY_QR, KEY_RIGHT
+from charcodes import KEY_QR, KEY_RIGHT, KEY_LEFT
SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22)
@@ -3561,4 +3561,68 @@ def test_unknown_input_script(stype, fake_txn , start_sign, cap_story, use_testn
assert title == "OK TO SEND?"
txin_explorer(len(ins), ins)
+
+def test_tx_explorer_goto_idx(fake_txn, start_sign, cap_story, use_testnet, need_keypress,
+ pick_menu_item, cap_screen, enter_number, press_cancel, is_q1):
+ use_testnet()
+ num_ins = 27
+ num_outs = 32
+
+ psbt = fake_txn(num_ins, num_outs, segwit_in=True, change_outputs=[0])
+ start_sign(psbt)
+ title, story = cap_story()
+ assert title == "OK TO SEND?"
+ need_keypress("2")
+ pick_menu_item("Inputs")
+ time.sleep(.1)
+ title, story = cap_story()
+ assert "(2)" in story
+
+ need_keypress("2")
+ time.sleep(.1)
+ scr = cap_screen()
+ assert f"0-{num_ins - 1}" in scr
+ enter_number(15)
+ time.sleep(.1)
+ title, story = cap_story()
+ assert title == "Input 15"
+
+ need_keypress("2")
+ enter_number(1)
+ time.sleep(.1)
+ title, story = cap_story()
+ assert title == "Input 1"
+
+ need_keypress("2")
+ enter_number(59) # over max
+ time.sleep(.1)
+ title, story = cap_story()
+ assert title == f"Input {num_ins - 1}"
+ press_cancel()
+
+ pick_menu_item("Outputs")
+ time.sleep(.1)
+ title, story = cap_story()
+ assert "(2)" in story
+ need_keypress("2")
+ enter_number(4)
+ time.sleep(.1)
+ title, story = cap_story()
+ assert title == f"4-{4 + 10 - 1}"
+
+ # try to move left
+ need_keypress(KEY_LEFT if is_q1 else "7")
+
+ time.sleep(.1)
+ title, story = cap_story()
+ assert title == f"0-9"
+
+ need_keypress("2")
+ enter_number(59)
+ time.sleep(.1)
+ title, story = cap_story()
+ num = num_outs - 1
+ assert title == f"{num}-{num}"
+
+
# EOF
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.