addr.py: support extended MMGen IDs

This commit is contained in:
The MMGen Project 2025-10-26 10:35:49 +00:00
commit 797912283c
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
3 changed files with 55 additions and 2 deletions

View file

@ -23,7 +23,7 @@ addr: MMGen address-related types
from collections import namedtuple
from .objmethods import HiliteStr, InitErrors, MMGenObject
from .obj import ImmutableAttr, MMGenIdx, get_obj
from .obj import ImmutableAttr, MMGenIdx, Int, get_obj
from .seed import SeedID
from . import color as color_mod
@ -93,6 +93,10 @@ class MMGenPasswordType(MMGenAddrType):
class AddrIdx(MMGenIdx):
max_digits = 7
class MoneroIdx(Int):
max_digits = 5
min_val = 0
def is_addr_idx(s):
return get_obj(AddrIdx, n=s, silent=True, return_bool=True)
@ -136,7 +140,14 @@ class MMGenID(HiliteStr, InitErrors, MMGenObject):
mmtype = proto.dfl_mmtype
case _:
raise ValueError('not 2 or 3 colon-separated items')
me = str.__new__(cls, f'{sid}:{mmtype}:{idx}')
if '-' in idx: # extended Monero ID
assert proto.coin == 'XMR', 'extended MMGen IDs supported for XMR only'
assert id_str.count(':') == 2, 'mmtype letter required for extended MMGen IDs'
me = str.__new__(cls, id_str)
idx, ext = idx.split('-', 1)
me.acct_num, me.acct_addr_num = [MoneroIdx(e) for e in ext.split('/', 1)]
else:
me = str.__new__(cls, f'{sid}:{mmtype}:{idx}')
me.sid = SeedID(sid=sid)
me.mmtype = proto.addr_type(mmtype)
me.idx = AddrIdx(idx)

View file

@ -176,6 +176,7 @@ tests = {
{'id_str': 'x:L:3', 'proto': proto},
{'id_str': 'F00BAA12', 'proto': proto},
{'id_str': 'F00BAA12:Z:99', 'proto': proto},
{'id_str': 'F00BAA12:B:1-0/0', 'proto': proto},
),
'good': (
{'id_str': 'F00BAA12:99', 'proto': proto, 'ret': 'F00BAA12:L:99'},

41
test/objtest_d/xmr_mainnet.py Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env python3
#
# MMGen Wallet, a terminal-based cryptocurrency wallet
# Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
"""
test.objtest_d.xmr_mainnet: XMR mainnet test vectors for MMGen data objects
"""
from mmgen.protocol import init_proto
from mmgen.addr import MMGenID
from ..include.common import cfg
proto = init_proto(cfg, 'xmr', need_amt=True)
tests = {
'MMGenID': {
'arg1': 'id_str',
'bad': (
{'id_str': 'F00BAA12', 'proto': proto},
{'id_str': 'F00BAA12:C:99', 'proto': proto},
{'id_str': 'F00BAA12:M', 'proto': proto},
{'id_str': 'F00BAA12:M:', 'proto': proto},
{'id_str': 'F00BAA12:M:99-FOO', 'proto': proto},
{'id_str': 'F00BAA12:M:99-1', 'proto': proto},
{'id_str': 'F00BAA12:M:99-x/y', 'proto': proto},
{'id_str': 'F00BAA12:M:99-1/y', 'proto': proto},
{'id_str': 'F00BAA12:M:0-1/1', 'proto': proto},
{'id_str': 'F00BAA12:M:1-0/-1', 'proto': proto},
{'id_str': 'F00BAA12:1-0/0', 'proto': proto},
{'id_str': 'F00BAA12:M:1-111111/3', 'proto': proto},
),
'good': (
{'id_str': 'F00BAA12:M:1', 'proto': proto},
{'id_str': 'F00BAA12:M:1-0/0', 'proto': proto},
{'id_str': 'F00BAA12:M:9999999-99999/99999', 'proto': proto},
),
},
}