bugfix: Mk4: export loop for devices with NFC=ViDsk=0

This commit is contained in:
scgbckbone 2025-04-28 11:04:35 +02:00 committed by doc-hex
parent bee2f95e0a
commit 6c0ee684dc
6 changed files with 37 additions and 17 deletions

View File

@ -11,7 +11,7 @@ This lists the new changes that have not yet been published in a normal release.
## 5.4.? - 2025-05-
- tbd
- Bugfix: Mk4 with both NFC & Virtual Disk OFF cannot exit `Export Wallet` menu. Stuck in export loop - needs reboot.
# Q Specific Changes

View File

@ -39,7 +39,7 @@ async def export_contents(title, contents, fname_pattern, derive=None, addr_fmt=
# produces signed export in case of SD/Vdisk (signed with key at deriv and addr_fmt)
# checks if suitable to offer QR export on Mk4
# argument contents can support function that generates content
from glob import dis, NFC
from glob import dis, NFC, VD
from files import CardSlot, CardMissingError, needs_microsd
from qrs import MAX_V11_CHAR_LIMIT
@ -94,6 +94,9 @@ async def export_contents(title, contents, fname_pattern, derive=None, addr_fmt=
msg += "\n\n%s signature file written:\n\n%s" % (title, sig_nice)
await ux_show_story(msg)
if no_qr and (NFC is None) and (VD is None) and not force_prompt:
# user has no other ways enabled, we already exported to SD - done
return
def generate_public_contents():
# Generate public details about wallet.

View File

@ -400,7 +400,7 @@ def export_prompt_builder(what_it_is, no_qr=False, no_nfc=False, key0=None, offe
prompt, escape = None, KEY_CANCEL+"x"
if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt or offer_kt:
if (NFC or VD) or (num_sd_slots>1) or key0 or force_prompt or offer_kt or txid or (not no_qr):
# no need to spam with another prompt, only option is SD card
prompt = "Press (1) to save %s to SD Card" % what_it_is

View File

@ -1666,11 +1666,17 @@ def enable_nfc(needs_nfc, sim_exec, settings_set):
return doit
@pytest.fixture()
def nfc_disabled(needs_nfc, settings_get):
def nfc_disabled(settings_get):
def doit():
return not bool(settings_get('nfc', 0))
return doit
@pytest.fixture()
def vdisk_disabled(settings_get):
def doit():
return not bool(settings_get('vidsk', 0))
return doit
@pytest.fixture()
def scan_a_qr(sim_exec, is_q1):
# simulate a QR being scanned
@ -2477,16 +2483,18 @@ def txout_explorer(cap_story, press_cancel, need_keypress, is_q1):
@pytest.fixture
def skip_if_useless_way(is_q1, nfc_disabled):
def skip_if_useless_way(is_q1, nfc_disabled, vdisk_disabled):
# when NFC is disabled, no point trying to do a PSBT via NFC
# - important: run_sim_tests.py will enable NFC for complete testing
# - similarly: the Mk4 and earlier had no QR scanner, so cannot use that as input
def doit(way):
if way == "qr" and not is_q1:
raise pytest.skip("mk4 QR not supported")
if way == 'nfc' and nfc_disabled():
elif way == 'nfc' and nfc_disabled():
# runner will test these cases, but fail faster otherwise
raise pytest.skip("NFC disabled")
elif way == "vdisk" and vdisk_disabled():
raise pytest.skip("VirtualDisk disabled")
return doit

View File

@ -81,7 +81,10 @@ def test_addr_vs_bitcoind(use_regtest, press_select, dev, bitcoind_d_sim_sign):
("m/0/0/0/0/0/0/0/0/0/0/0/0/0\np2pkh", "too deep"),
("m/0/0/0/0/0/q/0/0/0\np2pkh", "invalid characters"),
])
def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_text, cap_story):
def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_text, cap_story,
skip_if_useless_way):
skip_if_useless_way("nfc")
body, err = body_err
goto_home()
pick_menu_item('Advanced/Tools')
@ -96,7 +99,9 @@ def test_show_addr_nfc_invalid(body_err, goto_home, pick_menu_item, nfc_write_te
@pytest.mark.parametrize("str_addr_fmt", ["p2pkh", "", "p2wpkh", "p2wpkh-p2sh", "p2sh-p2wpkh"])
def test_show_addr_nfc(path, str_addr_fmt, nfc_write_text, nfc_read_text, pick_menu_item,
goto_home, cap_story, press_nfc, addr_vs_path, press_select, is_q1,
cap_screen):
cap_screen, skip_if_useless_way):
skip_if_useless_way("nfc")
# import pdb;pdb.set_trace()
for _ in range(5):
# need to wait for ApproveMessageSign to be popped from ux stack

View File

@ -525,7 +525,7 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, mi
def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home,
cap_story, need_keypress, enter_number, cap_screen_qr,
settings_set, nfc_read_text, is_q1, press_select, press_cancel,
press_nfc, expect_acctnum_captured):
press_nfc, expect_acctnum_captured, nfc_disabled):
# XPUB's via QR
settings_set("chain", chain)
chain_num = 0 if chain == "BTC" else 1
@ -553,12 +553,13 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home,
if is_xfp:
got = cap_screen_qr().decode('ascii')
time.sleep(.1)
press_nfc()
time.sleep(.2)
nfc_got = nfc_read_text()
time.sleep(.2)
assert nfc_got == got == xfp2str(simulator_fixed_xfp).upper()
press_cancel() # cancel animation
if not nfc_disabled():
press_nfc()
time.sleep(.2)
nfc_got = nfc_read_text()
time.sleep(.2)
assert nfc_got == got == xfp2str(simulator_fixed_xfp).upper()
press_cancel() # cancel animation
press_cancel() # cancel QR
continue
@ -590,9 +591,10 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home,
got_nfc_pub = nfc_read_text()
time.sleep(0.1)
press_cancel() # cancel animation
press_cancel() # cancel QR
assert got_nfc_pub == got_pub
press_cancel() # cancel QR
time.sleep(.1)
_, story = cap_story()
assert got_pub[0] in 'xt'
@ -641,7 +643,9 @@ def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home,
def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home,
settings_set, need_keypress, expect_acctnum_captured, OK,
pick_menu_item, way, cap_story, cap_menu, int_ext, settings_get,
virtdisk_path, load_export, press_select):
virtdisk_path, load_export, press_select, skip_if_useless_way):
skip_if_useless_way(way)
settings_set('chain', chain)
chain_num = 1 if chain in ["XTN", "XRT"] else 0