docs & nits

This commit is contained in:
scgbckbone 2025-05-22 12:00:05 +02:00
parent e01822c25e
commit 8e90fe67b0
6 changed files with 47 additions and 26 deletions

11
docs/bip-21-extensions.md Normal file
View File

@ -0,0 +1,11 @@
## `wallet` Ownership address check
Address ownership allows to specify particular multisig wallet in which to search, allowing to skip
useless searches in irrelevant wallets. `wallet` query parameter is provided via [BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki)
#### Examples:
```
tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=my_wal
'mtHSVByP9EYZmB26jASDdPVm19gvpecb5R?label=coldcard_purchase&amount=50&wallet=multi_wsh',
```

View File

@ -402,10 +402,8 @@ def generate_address_csv(path, addr_fmt, ms_wallet, account_num, n, start=0, cha
from ownership import OWNERSHIP
if ms_wallet:
if (start == 0) and (n > 100) and change in (0, 1):
saver = OWNERSHIP.saver(ms_wallet, change, start, n)
else:
saver = None
# saver will be None if we don't think it worth saving these addresses
saver = OWNERSHIP.saver(ms_wallet, change, start, n)
for line in ms_wallet.generate_address_csv(start, n, change):
yield line
@ -419,6 +417,7 @@ def generate_address_csv(path, addr_fmt, ms_wallet, account_num, n, start=0, cha
from wallet import MasterSingleSigWallet
main = MasterSingleSigWallet(addr_fmt, path, account_num)
# saver will be None if we don't think it worth saving these addresses
saver = OWNERSHIP.saver(main, change, start, n)
yield '"Index","Payment Address","Derivation"\n'

View File

@ -161,9 +161,8 @@ class Display:
self.text(None, y, msg, font=FontLarge)
if line2:
y += FontLarge.height # add height of above
y += FontTiny.height # add space of size FontTiny height
self.text(None, y, line2, font=FontSmall)
# 21 + 6 ie. FontLarge.height of above text + FontTiny.height as space between
self.text(None, y + 27, line2, font=FontSmall)
if percent is not None:
self.progress_bar(percent)

View File

@ -39,6 +39,7 @@ OWNERSHIP_MAGIC = 0x10A0 # "Address Ownership" v1.0
# target 3 flash blocks, max file size => 764 addresses
MAX_ADDRS_STORED = const(764) # =((3*512) - OWNERSHIP_FILE_HDR_LEN) // HASH_ENC_LEN
BONUS_AFTER_MATCH = const(20) # number of addresses to still generate after match found
def encode_addr(addr, salt):
# Convert text address to something we can store while preserving privacy.
@ -161,7 +162,7 @@ class AddressCacheFile:
self.count += 1
if bonus:
if bonus >= 20:
if bonus >= BONUS_AFTER_MATCH:
# do (at most) 20 more - limited by 'start_idx' & 'count'
break
bonus += 1
@ -317,11 +318,8 @@ class OwnershipCache:
cachefs.append(AddressCacheFile(w, 1))
for cf in cachefs:
msg, l2 = "Searching...", "(change)" if cf.change_idx else None
if dis.has_lcd:
msg, l2 = 'Searching wallet(s)...', cf.nice_name()
dis.fullscreen(msg, line2=l2)
msg = "Searching wallet(s)..." if dis.has_lcd else "Searching..."
dis.fullscreen(msg, line2=cf.nice_name())
wallet, subpath = OWNERSHIP.search_wallet_cache(addr, cf)
if wallet:
# first arg from_cache=True
@ -330,11 +328,8 @@ class OwnershipCache:
# nothing found in existing cache files
c = 0
for cf in cachefs:
msg, l2 = "Generating...", "(change)" if cf.change_idx else None
if dis.has_lcd:
msg, l2 = 'Generating addresses...', cf.nice_name()
dis.fullscreen(msg, line2=l2)
msg = "Generating addresses..." if dis.has_lcd else "Generating..."
dis.fullscreen(msg, line2=cf.nice_name())
wallet, subpath = OWNERSHIP.search_build_wallet(addr, cf)
c += cf.count
if wallet:

View File

@ -63,6 +63,13 @@ class MasterSingleSigWallet(WalletABC):
# - path can be overriden when we come here via address explorer
n = chains.addr_fmt_label(addr_fmt)
if not version.has_qwerty:
# Mk4 tiny display
# Classic P2PKH -> P2PKH
# Segwit P2WPKH -> P2WPKH
# P2SH-Segwit -> no change (should not be used that much)
n = n.split(" ")[-1]
purpose = chains.af_to_bip44_purpose(addr_fmt)
prefix = path or 'm/%dh/{coin_type}h/{account}h' % purpose
@ -72,12 +79,13 @@ class MasterSingleSigWallet(WalletABC):
self.chain = chains.current_chain()
if account_idx != 0:
n += ' Account#%d' % account_idx
rv = " Account#%d" if version.has_qwerty else " Acct#%d"
n += rv % account_idx
if self.chain.ctype == 'XTN':
n += ' (Testnet)'
n += ' (Testnet)' if version.has_qwerty else " XTN"
if self.chain.ctype == 'XRT':
n += ' (Regtest)'
n += ' (Regtest)' if version.has_qwerty else " XRT"
self.name = n
self.addr_fmt = addr_fmt

View File

@ -59,15 +59,18 @@ def test_negative(addr_fmt, testnet, sim_exec):
@pytest.mark.parametrize('from_empty', [ True, False] )
def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx,
sim_exec, wipe_cache, make_myself_wallet, use_testnet, goto_home, pick_menu_item,
enter_number, press_cancel, settings_set, import_ms_wallet, clear_miniscript
enter_number, press_cancel, settings_set, import_ms_wallet, clear_miniscript, is_q1,
):
# API/Unit test, limited UX
ms_addr_fmts = { AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH }
if (addr_fmt in ms_addr_fmts) and subaccount:
raise pytest.skip('multisig with subaccount')
if chain == "BTC":
use_testnet(False)
testnet = False
if addr_fmt in { AF_P2WSH, AF_P2SH, AF_P2WSH_P2SH }:
if addr_fmt in ms_addr_fmts:
# multisig jigs assume testnet
raise pytest.skip('testnet only')
@ -168,10 +171,16 @@ def test_positive(addr_fmt, offset, subaccount, chain, from_empty, change_idx,
from_cache, got_name, got_path = lst
assert from_cache == (not from_empty)
assert expect_name in got_name
if subaccount and '...' not in path:
if is_q1:
assert expect_name in got_name
else:
assert expect_name.split(" ")[-1] in got_name
if subaccount:
# not expected for multisig, since we have proper wallet name
assert f'Account#{subaccount}' in got_name
if is_q1:
assert f'Account#{subaccount}' in got_name
else:
assert f'Acct#{subaccount}' in got_name
assert got_path == (change_idx, offset)