unify address format labels; address explorer now uses both labels and shortened addresses; axi updated to track last 4 addr chars or MenuItem label (multisig)

(cherry picked from commit 63debfebaf)
This commit is contained in:
scgbckbone 2023-05-10 11:33:41 +02:00 committed by doc-hex
parent b05bd09998
commit aa7d17bf8f
8 changed files with 81 additions and 45 deletions

View File

@ -9,7 +9,7 @@ from uhashlib import sha256
from uasyncio import sleep_ms
from ubinascii import hexlify as b2a_hex
from utils import imported, pretty_short_delay, problem_file_line, import_prompt_builder
from utils import xfp2str, decrypt_tapsigner_backup, B2A
from utils import xfp2str, decrypt_tapsigner_backup, B2A, addr_fmt_label
from ux import ux_show_story, the_ux, ux_confirm, ux_dramatic_pause, ux_aborted
from ux import ux_enter_bip32_index, ux_input_text
from export import make_json_wallet, make_summary_file, make_descriptor_wallet_export
@ -1095,9 +1095,12 @@ async def electrum_skeleton(*a):
# 'classic' instead of 'legacy' personallly.
rv = []
rv.append(MenuItem("Legacy (P2PKH)", f=electrum_skeleton_step2, arg=(AF_CLASSIC, account_num)))
rv.append(MenuItem("P2SH-Segwit", f=electrum_skeleton_step2, arg=(AF_P2WPKH_P2SH, account_num)))
rv.append(MenuItem("Native Segwit", f=electrum_skeleton_step2, arg=(AF_P2WPKH, account_num)))
rv.append(MenuItem(addr_fmt_label(AF_CLASSIC), f=electrum_skeleton_step2,
arg=(AF_CLASSIC, account_num)))
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=electrum_skeleton_step2,
arg=(AF_P2WPKH_P2SH, account_num)))
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH), f=electrum_skeleton_step2,
arg=(AF_P2WPKH, account_num)))
return MenuSystem(rv)
@ -1134,16 +1137,15 @@ async def ss_descriptor_skeleton(label, _, item):
# 'classic' instead of 'legacy' personallly.
rv = []
rv.append(MenuItem("Legacy (P2PKH)", f=descriptor_skeleton_step2,
rv.append(MenuItem(addr_fmt_label(AF_CLASSIC), f=descriptor_skeleton_step2,
arg=(AF_CLASSIC, account_num, int_ext)))
rv.append(MenuItem("P2SH-Segwit", f=descriptor_skeleton_step2,
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=descriptor_skeleton_step2,
arg=(AF_P2WPKH_P2SH, account_num, int_ext)))
rv.append(MenuItem("Native Segwit", f=descriptor_skeleton_step2,
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH), f=descriptor_skeleton_step2,
arg=(AF_P2WPKH, account_num, int_ext)))
rv.append(MenuItem("Taproot (P2TR)", f=descriptor_skeleton_step2,
rv.append(MenuItem(addr_fmt_label(AF_P2TR), f=descriptor_skeleton_step2,
arg=(AF_P2TR, account_num, int_ext)))
return MenuSystem(rv)
async def samourai_post_mix_descriptor_export(*a):

View File

@ -14,6 +14,7 @@ from uhashlib import sha256
from ubinascii import hexlify as b2a_hex
from glob import settings
from auth import write_sig_file
from utils import addr_fmt_label
def truncate_address(addr):
# Truncates address to width of screen, replacing middle chars
@ -98,10 +99,10 @@ class PickAddrFmtMenu(MenuSystem):
def __init__(self, path, parent):
self.parent = parent
items = [
MenuItem("Classic P2PKH", f=self.done, arg=(path, AF_CLASSIC)),
MenuItem("Segwit P2WPKH", f=self.done, arg=(path, AF_P2WPKH)),
MenuItem("P2SH-P2WPKH", f=self.done, arg=(path, AF_P2WPKH_P2SH)),
MenuItem("Taproot P2TR", f=self.done, arg=(path, AF_P2TR)),
MenuItem(addr_fmt_label(AF_CLASSIC), f=self.done, arg=(path, AF_CLASSIC)),
MenuItem(addr_fmt_label(AF_P2WPKH), f=self.done, arg=(path, AF_P2WPKH)),
MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=self.done, arg=(path, AF_P2WPKH_P2SH)),
MenuItem(addr_fmt_label(AF_P2TR), f=self.done, arg=(path, AF_P2TR)),
]
super().__init__(items)
if path.startswith("m/84'"):
@ -181,10 +182,15 @@ class AddressListMenu(MenuSystem):
stash.blank_object(node)
items = [MenuItem(address, f=self.pick_single, arg=(path, addr_fmt))
for i, (address, path, addr_fmt) in enumerate(choices)]
items = []
for i, (address, path, addr_fmt) in enumerate(choices):
axi = address[-4:] # last 4 address characters
items.append(MenuItem(" "+addr_fmt_label(addr_fmt), f=self.pick_single,
arg=(path, addr_fmt, axi)))
items.append(MenuItem(address, f=self.pick_single,
arg=(path, addr_fmt, axi)))
# some other choices
# some other choices
if self.account_num == 0:
items.append(MenuItem("Applications", menu=ApplicationsMenu(self)))
items.append(MenuItem("Account Number", f=self.change_account))
@ -197,22 +203,27 @@ class AddressListMenu(MenuSystem):
else:
items.append(MenuItem("Account: %d" % self.account_num, f=self.change_account))
self.goto_idx(settings.get('axi', 0)) # weak
self.replace_items(items)
axi = settings.get('axi', 0)
if isinstance(axi, str):
ok = self.goto_label(axi)
if not ok:
self.goto_idx(0)
else:
self.goto_idx(axi)
async def change_account(self, *a):
self.account_num = await ux_enter_bip32_index('Account Number:') or 0
await self.render()
async def pick_single(self, _1, menu_idx, item):
settings.put('axi', menu_idx) # update last clicked address
path, addr_fmt = item.arg
async def pick_single(self, _1, _2, item):
path, addr_fmt, axi = item.arg
settings.put('axi', axi) # update last clicked address
await self.show_n_addresses(path, addr_fmt, None)
async def pick_multisig(self, _1, menu_idx, item):
async def pick_multisig(self, _1, _2, item):
ms_wallet = item.arg
settings.put('axi', menu_idx) # update last clicked address
settings.put('axi', item.label) # update last clicked address
await self.show_n_addresses(None, None, ms_wallet)
async def make_custom(self, *a):

View File

@ -166,9 +166,17 @@ class MenuSystem:
if not keep_position:
self.cursor = 0
self.ypos = 0
self.items = [m for m in menu_items if not getattr(m, 'predicate', None) or m.predicate()]
self.count = len(self.items)
def goto_label(self, label):
for i, m in enumerate(self.items):
if m.label == label or m.label[-4:] == label:
self.goto_idx(i)
return True
return False
def show(self):
#
# Redraw the menu.

View File

@ -53,9 +53,9 @@ class PaperWalletMaker:
self.is_taproot = False
def atype(self):
if self.is_taproot: return 2, 'Taproot Address'
if self.is_segwit: return 1, 'Segwit Address'
return 0, 'Classic Address'
if self.is_taproot: return 2, 'Taproot P2TR'
if self.is_segwit: return 1, 'Segwit P2WPKH'
return 0, 'Classic P2PKPH'
async def pick_template(self, *a):
fn = await file_picker('Pick PDF template to use, or X for none.',
@ -71,7 +71,7 @@ class PaperWalletMaker:
self.is_segwit = idx == 1
self.is_taproot = idx == 2
self.update_menu()
return self.atype()[0], ['Classic', 'Segwit/Bech32', 'Taproot'], set
return self.atype()[0], ['Classic P2PKPH', 'Segwit P2WPKH', 'Taproot P2TR'], set
@staticmethod
def can_do_qr():

View File

@ -539,4 +539,12 @@ def decrypt_tapsigner_backup(backup_key, data):
return decrypted.split("\n")
def addr_fmt_label(addr_fmt):
return {
AF_CLASSIC: "Classic P2PKH",
AF_P2WPKH_P2SH: "P2SH-Segwit",
AF_P2WPKH: "Segwit P2WPKH",
AF_P2TR: "Taproot P2TR"
}[addr_fmt]
# EOF

View File

@ -3,6 +3,8 @@
import pytest, time, io, csv
from ckcc_protocol.constants import *
from pycoin.key.BIP32Node import BIP32Node
from pycoin.contrib.segwit_addr import encode as sw_encode
from pycoin.encoding import a2b_hashed_base58, hash160
@pytest.fixture
@ -154,14 +156,15 @@ def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, cap_menu,
need_keypress('4')
time.sleep(.01)
m = cap_menu()
gap = iter(range(1, 10))
for idx, (path, addr_format) in enumerate(common_derivs):
# derive index=0 address
_id = next(gap) + idx
subpath = path.format(account=0, change=0, idx=0) # e.g. "m/44'/1'/0'/0/0"
sk = node_prv.subkey_for_path(subpath[2:])
# capture full index=0 address from display screen & validate it
goto_address_explorer(click_idx=idx)
goto_address_explorer(click_idx=_id)
addr_dict = parse_display_screen(0, 10)
if subpath not in addr_dict:
raise Exception('Subpath ("%s") not found in address explorer display' % subpath)
@ -169,7 +172,7 @@ def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, cap_menu,
validate_address(expected_addr, sk)
# validate that stub is correct
[start, end] = m[idx].split('-')
[start, end] = m[_id].split('-')
assert expected_addr.startswith(start)
assert expected_addr.endswith(end)
@ -191,7 +194,7 @@ def test_applications_samourai(chain, change, option, goto_address_explorer, cap
node_prv = BIP32Node.from_wallet_key(
sim_execfile('devtest/dump_private.py').strip()
)
goto_address_explorer(click_idx=4) # "applications" at index 3
goto_address_explorer(click_idx=6) # "applications" at index 3
menu = cap_menu()
assert "Samourai" in menu
pick_menu_item("Samourai")
@ -224,8 +227,10 @@ def test_address_display(goto_address_explorer, parse_display_screen, mk_common_
sim_execfile('devtest/dump_private.py').strip()
)
common_derivs = mk_common_derivations(node_prv.netcode())
gap = iter(range(1, 10))
for click_idx, (path, addr_format) in enumerate(common_derivs):
# Click on specified derivation idx in explorer
_id = next(gap) + click_idx
goto_address_explorer(click_idx=click_idx)
# perform keypad press sequence
@ -239,7 +244,7 @@ def test_address_display(goto_address_explorer, parse_display_screen, mk_common_
sk = node_prv.subkey_for_path(subpath[2:])
validate_address(given_addr, sk)
@pytest.mark.parametrize('click_idx', range(4))
@pytest.mark.parametrize('click_idx', [1,3,5,7])
@pytest.mark.parametrize("change", [True, False])
@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"])
def test_dump_addresses(way, change, generate_addresses_file, mk_common_derivations, sim_execfile, validate_address,
@ -286,7 +291,9 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
assert f'Account: {account_num}' in m
which = 0
gap = iter(range(1,10))
for idx, (path, addr_format) in enumerate(common_derivs):
_id = next(gap) + idx
# derive index=0 address
assert '{account}' in path
@ -297,7 +304,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
# go down menu to expected derivation spot
m = cap_menu()
pick_menu_item(m[idx])
pick_menu_item(m[_id])
time.sleep(0.1)
addr_dict = parse_display_screen(0, 10)
@ -307,7 +314,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
validate_address(expected_addr, sk)
# validate that stub is correct
[start, end] = m[idx].split('-')
[start, end] = m[_id].split('-')
assert expected_addr.startswith(start)
assert expected_addr.endswith(end)
@ -388,14 +395,14 @@ def test_custom_path(path, which_fmt, addr_vs_path, pick_menu_item, goto_address
m = cap_menu()
assert m[0] == 'Classic P2PKH'
assert m[1] == 'Segwit P2WPKH'
assert m[2] == 'P2SH-P2WPKH'
assert m[2] == 'P2SH-Segwit'
assert m[3] == 'Taproot P2TR'
fmts = {
AF_CLASSIC: 'Classic P2PKH',
AF_P2WPKH: 'Segwit P2WPKH',
AF_P2TR: 'Taproot P2TR',
AF_P2WPKH_P2SH: 'P2SH-P2WPKH',
AF_P2WPKH_P2SH: 'P2SH-Segwit',
}
pick_menu_item(fmts[which_fmt])
@ -486,7 +493,7 @@ def test_bitcoind_descriptor_address(addr_fmt, acct_num, bitcoind, goto_home, pi
sig_check = True
if addr_fmt == AF_P2WPKH:
menu_item = "Native Segwit"
menu_item = "Segwit P2WPKH"
desc_prefix = "wpkh("
click_idx = 2
elif addr_fmt == AF_P2WPKH_P2SH:
@ -494,13 +501,13 @@ def test_bitcoind_descriptor_address(addr_fmt, acct_num, bitcoind, goto_home, pi
desc_prefix = "sh(wpkh("
click_idx = 1
elif addr_fmt == AF_P2TR:
menu_item = "Taproot (P2TR)"
menu_item = "Taproot P2TR"
desc_prefix = "tr("
click_idx = 3
sig_check = False
else:
# addr_fmt == AF_CLASSIC:
menu_item = "Legacy (P2PKH)"
menu_item = "Classic P2PKH"
desc_prefix = "pkh("
click_idx = 0

View File

@ -220,7 +220,7 @@ def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, need_keyp
assert got.sec() == expect.sec()
@pytest.mark.parametrize('mode', [ "Legacy (P2PKH)", "P2SH-Segwit", "Native Segwit"])
@pytest.mark.parametrize('mode', [ "Classic P2PKH", "P2SH-Segwit", "Segwit P2WPKH"])
@pytest.mark.parametrize('acct_num', [ None, '0', '9897'])
@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"])
@pytest.mark.parametrize('testnet', [True, False])
@ -606,7 +606,7 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting
menu = cap_menu()
if addr_fmt == AF_P2WPKH:
menu_item = "Native Segwit"
menu_item = "Segwit P2WPKH"
desc_prefix = "wpkh("
bip44_purpose = 84
elif addr_fmt == AF_P2WPKH_P2SH:
@ -619,7 +619,7 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting
bip44_purpose = 86
else:
# addr_fmt == AF_CLASSIC:
menu_item = "Legacy (P2PKH)"
menu_item = "Classic P2PKH"
desc_prefix = "pkh("
bip44_purpose = 44
@ -673,7 +673,7 @@ def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_
need_keypress(ch)
need_keypress("y")
need_keypress("y") # int_ext <0;1>
pick_menu_item("Native Segwit") # both postmix and premix are p2wpkh only
pick_menu_item("Segwit P2WPKH") # both postmix and premix are p2wpkh only
file_desc_generic = load_export("sd", label="Descriptor", is_json=False, addr_fmt=AF_P2WPKH)
need_keypress("y") # written
need_keypress("x") # go back to advanced

View File

@ -40,8 +40,8 @@ def test_generate(mode, chain, pdf, cap_menu, pick_menu_item, goto_home, cap_sto
time.sleep(0.1)
if mode == 'segwit':
pick_menu_item('Classic Address')
pick_menu_item('Segwit/Bech32')
pick_menu_item('Classic P2PKH')
pick_menu_item('Segwit P2WPKH')
time.sleep(0.5)
if mode == 'taproot':