import cleanups throughout
This commit is contained in:
parent
753bd0aba8
commit
ad569cbeb7
18 changed files with 98 additions and 61 deletions
|
|
@ -23,8 +23,6 @@ amt.py: MMGen CoinAmt and related classes
|
|||
from decimal import Decimal
|
||||
from .objmethods import Hilite,InitErrors
|
||||
|
||||
class UnknownCoinAmt(Decimal): pass
|
||||
|
||||
class DecimalNegateResult(Decimal): pass
|
||||
|
||||
class CoinAmt(Decimal,Hilite,InitErrors): # abstract class
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@ baseconv.py: base conversion class for the MMGen suite
|
|||
"""
|
||||
|
||||
from hashlib import sha256
|
||||
from .exception import *
|
||||
from .util import die
|
||||
from collections import namedtuple
|
||||
|
||||
from .exception import BaseConversionError,BaseConversionPadError,HexadecimalStringError,SeedLengthError
|
||||
from .util import die
|
||||
|
||||
def is_b58_str(s):
|
||||
return set(list(s)) <= set(baseconv('b58').digits)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ bip39.py - Data and routines for BIP39 mnemonic seed phrases
|
|||
|
||||
from hashlib import sha256
|
||||
|
||||
from .exception import *
|
||||
from .exception import MnemonicError
|
||||
from .baseconv import baseconv
|
||||
from .util import is_hex_str
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@
|
|||
daemon.py: Daemon control interface for the MMGen suite
|
||||
"""
|
||||
|
||||
import shutil
|
||||
import os,shutil,time
|
||||
from subprocess import run,PIPE,CompletedProcess
|
||||
from collections import namedtuple
|
||||
from .exception import *
|
||||
from .common import *
|
||||
|
||||
from .globalvars import g
|
||||
from .opts import opt
|
||||
from .util import msg,die,list_gen,get_subclasses
|
||||
from .flags import *
|
||||
|
||||
_dd = namedtuple('daemon_data',['coind_name','coind_version','coind_version_str']) # latest tested version
|
||||
|
|
@ -78,6 +80,7 @@ class Daemon(Lockable):
|
|||
try:
|
||||
cp = run(cmd,check=False,stdout=out,stderr=out)
|
||||
except Exception as e:
|
||||
from .exception import MMGenCalledProcessError
|
||||
raise MMGenCalledProcessError(f'Error starting executable: {type(e).__name__} [Errno {e.errno}]')
|
||||
if self.debug:
|
||||
print(cp)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ fileutil.py: Routines that read, write, execute or stat files
|
|||
import sys,os
|
||||
|
||||
from .globalvars import g
|
||||
from .exception import FileNotFound,MaxInputSizeExceeded
|
||||
from .util import (
|
||||
msg,
|
||||
qmsg,
|
||||
|
|
@ -90,6 +89,7 @@ def _check_file_type_and_access(fname,ftype,blkdev_ok=False):
|
|||
try:
|
||||
mode = os.stat(fname).st_mode
|
||||
except:
|
||||
from .exception import FileNotFound
|
||||
raise FileNotFound(f'Requested {ftype} {fname!r} not found')
|
||||
|
||||
for t in ok_types:
|
||||
|
|
@ -289,6 +289,7 @@ def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False,q
|
|||
data = data.decode()
|
||||
|
||||
if len(data) == g.max_input_size + 1:
|
||||
from .exception import MaxInputSizeExceeded
|
||||
raise MaxInputSizeExceeded(f'Too much input data! Max input data size: {f.max_input_size} bytes')
|
||||
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import sys,os,time,signal,shutil
|
|||
from subprocess import run,PIPE,DEVNULL
|
||||
from stat import *
|
||||
|
||||
from .common import *
|
||||
|
||||
mountpoint = '/mnt/tx'
|
||||
tx_dir = '/mnt/tx/tx'
|
||||
part_label = 'MMGEN_TX'
|
||||
|
|
@ -35,10 +37,8 @@ mn_fmts = {
|
|||
}
|
||||
mn_fmt_dfl = 'mmgen'
|
||||
|
||||
from .common import *
|
||||
opts.UserOpts._set_ok += ('outdir','passwd_file')
|
||||
|
||||
prog_name = os.path.basename(sys.argv[0])
|
||||
opts_data = {
|
||||
'sets': [('stealth_led', True, 'led', True)],
|
||||
'text': {
|
||||
|
|
@ -118,7 +118,7 @@ This command is currently available only on Linux-based platforms.
|
|||
|
||||
cmd_args = opts.init(
|
||||
opts_data,
|
||||
add_opts = ['outdir','passwd_file'], # required, because in _set_ok
|
||||
add_opts = ['outdir','passwd_file'], # in _set_ok, so must be set
|
||||
init_opts = {
|
||||
'quiet': True,
|
||||
'out_fmt': 'wallet',
|
||||
|
|
@ -135,15 +135,12 @@ if opt.mnemonic_fmt:
|
|||
opt.mnemonic_fmt,
|
||||
fmt_list(mn_fmts,fmt='no_spc') ))
|
||||
|
||||
import mmgen.tx
|
||||
from .wallet import Wallet
|
||||
from .tx import MMGenTX
|
||||
from .txsign import txsign
|
||||
from .protocol import init_proto
|
||||
from .rpc import rpc_init
|
||||
|
||||
if g.test_suite:
|
||||
from .daemon import CoinDaemon
|
||||
|
||||
if opt.mountpoint:
|
||||
mountpoint = opt.mountpoint
|
||||
|
||||
|
|
@ -198,7 +195,6 @@ def do_umount():
|
|||
run(['umount',mountpoint],check=True)
|
||||
|
||||
async def sign_tx_file(txfile):
|
||||
from .tx import MMGenTX
|
||||
try:
|
||||
tx1 = MMGenTX.Unsigned(filename=txfile)
|
||||
if tx1.proto.sign_mode == 'daemon':
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ passwdlist.py: Password list class for the MMGen suite
|
|||
|
||||
from collections import namedtuple
|
||||
|
||||
from .exception import InvalidPasswdFormat
|
||||
from .util import ymsg,is_hex_str,is_int,keypress_confirm
|
||||
from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
|
||||
from .baseconv import baseconv,is_b32_str,is_b58_str
|
||||
|
|
@ -115,6 +114,7 @@ class PasswordList(AddrList):
|
|||
self.pw_fmt = pw_fmt
|
||||
self.pw_fmt_disp = pw_fmt
|
||||
if self.pw_fmt not in self.pw_info:
|
||||
from .exception import InvalidPasswdFormat
|
||||
raise InvalidPasswdFormat(
|
||||
'{!r}: invalid password format. Valid formats: {}'.format(
|
||||
self.pw_fmt,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ seedsplit.py: Seed split classes and methods for the MMGen suite
|
|||
|
||||
from .globalvars import g
|
||||
from .color import yellow
|
||||
from .exception import RangeError
|
||||
from .obj import MMGenPWIDString,MMGenIdx
|
||||
from .subseed import *
|
||||
|
||||
|
|
@ -81,6 +80,7 @@ class SeedShareList(SubSeedList):
|
|||
msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
|
||||
else:
|
||||
return ms
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('nonce range exceeded')
|
||||
|
||||
def last_share_debug(last_share):
|
||||
|
|
@ -109,6 +109,7 @@ class SeedShareList(SubSeedList):
|
|||
self.data['long'][ls.sid] = (count,nonce)
|
||||
break
|
||||
else:
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('nonce range exceeded')
|
||||
|
||||
if g.debug_subseed:
|
||||
|
|
@ -118,6 +119,7 @@ class SeedShareList(SubSeedList):
|
|||
|
||||
def get_share_by_idx(self,idx,base_seed=False):
|
||||
if idx < 1 or idx > self.count:
|
||||
from .exception import RangeError
|
||||
raise RangeError(f'{idx}: share index out of range')
|
||||
elif idx == self.count:
|
||||
return self.last_share
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ subseed.py: Subseed classes and methods for the MMGen suite
|
|||
|
||||
from .color import green
|
||||
from .util import msg_r,msg,qmsg
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
from .obj import MMGenRange,IndexedDict
|
||||
from .seed import *
|
||||
from .crypto import scramble_seed
|
||||
|
|
@ -192,6 +191,7 @@ class SubSeedList(MMGenObject):
|
|||
self.data[length][sid] = (idx,nonce)
|
||||
return last_sid == sid
|
||||
else: # must exit here, as this could leave self.data in inconsistent state
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded')
|
||||
|
||||
for idx in SubSeedIdxRange(first_idx,last_idx).iterate():
|
||||
|
|
|
|||
|
|
@ -20,19 +20,20 @@
|
|||
tool.py: Routines for the 'mmgen-tool' utility
|
||||
"""
|
||||
|
||||
from .protocol import hash160
|
||||
from .common import *
|
||||
from .protocol import hash160
|
||||
from .fileutil import get_seed_file,get_data_from_file,write_data_to_file
|
||||
from .crypto import get_random
|
||||
from .key import PrivKey
|
||||
from .subseed import SubSeedList
|
||||
from .seedsplit import MasterShareIdx
|
||||
from .addr import *
|
||||
from .addrlist import AddrList,KeyAddrList
|
||||
from .addrlist import AddrList,KeyAddrList,AddrIdxList
|
||||
from .passwdlist import PasswordList
|
||||
from .baseconv import baseconv
|
||||
from .xmrseed import xmrseed
|
||||
from .bip39 import bip39
|
||||
from .fileutil import get_seed_file,get_data_from_file,write_data_to_file
|
||||
from .tw import TwCommon
|
||||
|
||||
NL = ('\n','\r\n')[g.platform=='win']
|
||||
|
||||
|
|
@ -234,8 +235,6 @@ def _process_result(ret,pager=False,print_result=False):
|
|||
else:
|
||||
ydie(1,f'tool.py: can’t handle return value of type {type(ret).__name__!r}')
|
||||
|
||||
from .addr import MMGenAddrType
|
||||
|
||||
dfl_mnemonic_fmt = 'mmgen'
|
||||
mft = namedtuple('mnemonic_format',['fmt','pad','conv_cls'])
|
||||
mnemonic_fmts = {
|
||||
|
|
@ -895,7 +894,6 @@ class MMGenToolCmdWallet(MMGenToolCmds):
|
|||
ss = Wallet(sf)
|
||||
if ss.seed.sid != addr.sid:
|
||||
die(1,f'Seed ID of requested address ({addr.sid}) does not match wallet ({ss.seed.sid})')
|
||||
from .addrlist import AddrList,AddrIdxList
|
||||
al = AddrList(
|
||||
proto = self.proto,
|
||||
seed = ss.seed,
|
||||
|
|
@ -905,8 +903,6 @@ class MMGenToolCmdWallet(MMGenToolCmds):
|
|||
ret = d.sec.wif if target=='wif' else d.addr
|
||||
return ret
|
||||
|
||||
from .tw import TwCommon
|
||||
|
||||
class MMGenToolCmdRPC(MMGenToolCmds):
|
||||
"tracking wallet commands using the JSON-RPC interface"
|
||||
|
||||
|
|
@ -964,7 +960,6 @@ class MMGenToolCmdRPC(MMGenToolCmds):
|
|||
die(1,
|
||||
f'{mmgen_addrs}: invalid address list argument ' +
|
||||
'(must be in form <seed ID>:[<type>:]<idx list>)' )
|
||||
from .addrlist import AddrIdxList
|
||||
usr_addr_list = [MMGenID(self.proto,f'{a[0]}:{i}') for i in AddrIdxList(a[1])]
|
||||
|
||||
from .twaddrs import TwAddrList
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ twaddrs: Tracking wallet listaddresses class for the MMGen suite
|
|||
"""
|
||||
|
||||
from .color import green
|
||||
from .exception import BadAgeFormat
|
||||
from .util import msg,die,altcoin_subclass
|
||||
from .base_obj import AsyncInit
|
||||
from .obj import MMGenList,MMGenDict,TwComment
|
||||
|
|
@ -125,6 +124,7 @@ class TwAddrList(MMGenDict,TwCommon,metaclass=AsyncInit):
|
|||
if not self.has_age:
|
||||
show_age = False
|
||||
if age_fmt not in self.age_fmts:
|
||||
from .exception import BadAgeFormat
|
||||
raise BadAgeFormat(f'{age_fmt!r}: invalid age format (must be one of {self.age_fmts!r})')
|
||||
fs = '{mid}' + ('',' {addr}')[showbtcaddrs] + ' {cmt} {amt}' + ('',' {age}')[show_age]
|
||||
mmaddrs = [k for k in self.keys() if k.type == 'mmgen']
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ twctl: Tracking wallet control class for the MMGen suite
|
|||
"""
|
||||
|
||||
from .globalvars import g
|
||||
from .exception import WalletFileError
|
||||
from .util import msg,dmsg,write_mode,altcoin_subclass
|
||||
from .base_obj import AsyncInit
|
||||
from .objmethods import MMGenObject
|
||||
|
|
@ -62,6 +61,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
|
|||
self.init_empty()
|
||||
|
||||
if self.data['coin'] != self.proto.coin: # TODO remove?
|
||||
from .exception import WalletFileError
|
||||
raise WalletFileError(
|
||||
'Tracking wallet coin ({}) does not match current coin ({})!'.format(
|
||||
self.data['coin'],
|
||||
|
|
@ -98,6 +98,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
|
|||
self.init_empty()
|
||||
self.force_write()
|
||||
else:
|
||||
from .exception import WalletFileError
|
||||
raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data')
|
||||
else:
|
||||
self.upgrade_wallet_maybe()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ from collections import namedtuple
|
|||
|
||||
from .globalvars import g
|
||||
from .color import red,yellow,green
|
||||
from .exception import BadAgeFormat
|
||||
from .util import (
|
||||
msg,
|
||||
msg_r,
|
||||
|
|
@ -129,6 +128,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
|
|||
@age_fmt.setter
|
||||
def age_fmt(self,val):
|
||||
if val not in self.age_fmts:
|
||||
from .exception import BadAgeFormat
|
||||
raise BadAgeFormat(f'{val!r}: invalid age format (must be one of {self.age_fmts!r})')
|
||||
self._age_fmt = val
|
||||
|
||||
|
|
|
|||
45
mmgen/tx.py
45
mmgen/tx.py
|
|
@ -20,10 +20,45 @@
|
|||
tx.py: Transaction routines for the MMGen suite
|
||||
"""
|
||||
|
||||
import sys,os,json
|
||||
from stat import *
|
||||
from .common import *
|
||||
from .obj import *
|
||||
import sys,time
|
||||
from .globalvars import g
|
||||
from .opts import opt
|
||||
from .color import *
|
||||
from .util import (
|
||||
msg,
|
||||
ymsg,
|
||||
dmsg,
|
||||
vmsg,
|
||||
qmsg,
|
||||
msg_r,
|
||||
die,
|
||||
is_int,
|
||||
fmt,
|
||||
suf,
|
||||
altcoin_subclass,
|
||||
confirm_or_raise,
|
||||
remove_dups,
|
||||
get_extension,
|
||||
keypress_confirm,
|
||||
do_license_msg,
|
||||
line_input,
|
||||
make_chksum_6,
|
||||
make_timestamp,
|
||||
secs_to_dhms,
|
||||
)
|
||||
from .objmethods import MMGenObject
|
||||
from .obj import (
|
||||
ImmutableAttr,
|
||||
ListItemAttr,
|
||||
MMGenList,
|
||||
MMGenListItem,
|
||||
MMGenTxLabel,
|
||||
HexStr,
|
||||
MMGenTxID,
|
||||
MMGenDict,
|
||||
CoinTxID,
|
||||
get_obj,
|
||||
)
|
||||
from .addr import MMGenID,CoinAddr,is_mmgen_id,is_coin_addr
|
||||
|
||||
wmsg = lambda k: {
|
||||
|
|
@ -148,6 +183,7 @@ class DeserializedTX(dict,MMGenObject):
|
|||
return int(vbytes[::-1].hex(),16)
|
||||
|
||||
def make_txid(tx_bytes):
|
||||
from hashlib import sha256
|
||||
return sha256(sha256(tx_bytes).digest()).digest()[::-1].hex()
|
||||
|
||||
self.idx = 0
|
||||
|
|
@ -1356,6 +1392,7 @@ class MMGenTX:
|
|||
vmsg(f'\nVsize: {vsize} (true) {est_vsize} (estimated)')
|
||||
ratio = float(est_vsize) / vsize
|
||||
if not (0.95 < ratio < 1.05): # allow for 5% error
|
||||
from .exception import BadTxSizeEstimate
|
||||
raise BadTxSizeEstimate(fmt(f"""
|
||||
Estimated transaction vsize is {ratio:1.2f} times the true vsize
|
||||
Your transaction fee estimates will be inaccurate
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ txfile.py: Transaction file operations for the MMGen suite
|
|||
from .common import *
|
||||
from .obj import HexStr,MMGenTxID,CoinTxID,MMGenTxLabel
|
||||
from .tx import MMGenTxOutput,MMGenTxOutputList,MMGenTxInput,MMGenTxInputList
|
||||
from .amt import UnknownCoinAmt
|
||||
from .exception import MaxFileSizeExceeded
|
||||
|
||||
class MMGenTxFile:
|
||||
|
||||
|
|
@ -63,6 +61,7 @@ class MMGenTxFile:
|
|||
try:
|
||||
desc = 'data'
|
||||
if len(tx_data) > g.max_tx_file_size:
|
||||
from .exception import MaxFileSizeExceeded
|
||||
raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
|
||||
tx_data = tx_data.splitlines()
|
||||
assert len(tx_data) >= 5,'number of lines less than 5'
|
||||
|
|
@ -188,6 +187,7 @@ class MMGenTxFile:
|
|||
self.chksum = make_chksum_6(' '.join(lines))
|
||||
fmt_data = '\n'.join([self.chksum] + lines) + '\n'
|
||||
if len(fmt_data) > g.max_tx_file_size:
|
||||
from .exception import MaxFileSizeExceeded
|
||||
raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
|
||||
return fmt_data
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ from hashlib import sha256
|
|||
from string import hexdigits,digits
|
||||
|
||||
from .color import *
|
||||
from .exception import BadFileExtension,UserNonConfirmation
|
||||
from .globalvars import g
|
||||
from .opts import opt
|
||||
|
||||
CUR_HIDE = '\033[?25l'
|
||||
CUR_SHOW = '\033[?25h'
|
||||
|
|
@ -65,6 +65,24 @@ def gmsg(s): msg(green(s))
|
|||
def gmsg_r(s): msg_r(green(s))
|
||||
def bmsg(s): msg(blue(s))
|
||||
def bmsg_r(s): msg_r(blue(s))
|
||||
def qmsg(s,alt=None):
|
||||
if opt.quiet:
|
||||
if alt != None: msg(alt)
|
||||
else: msg(s)
|
||||
def qmsg_r(s,alt=None):
|
||||
if opt.quiet:
|
||||
if alt != None: msg_r(alt)
|
||||
else: msg_r(s)
|
||||
def vmsg(s,force=False):
|
||||
if opt.verbose or force: msg(s)
|
||||
def vmsg_r(s,force=False):
|
||||
if opt.verbose or force: msg_r(s)
|
||||
def Vmsg(s,force=False):
|
||||
if opt.verbose or force: Msg(s)
|
||||
def Vmsg_r(s,force=False):
|
||||
if opt.verbose or force: Msg_r(s)
|
||||
def dmsg(s):
|
||||
if opt.debug: msg(s)
|
||||
|
||||
def mmsg(*args):
|
||||
for d in args: Msg(repr(d))
|
||||
|
|
@ -239,27 +257,6 @@ def parse_bytespec(nbytes):
|
|||
|
||||
die(1,f'{nbytes!r}: invalid byte specifier')
|
||||
|
||||
from .opts import opt
|
||||
|
||||
def qmsg(s,alt=None):
|
||||
if opt.quiet:
|
||||
if alt != None: msg(alt)
|
||||
else: msg(s)
|
||||
def qmsg_r(s,alt=None):
|
||||
if opt.quiet:
|
||||
if alt != None: msg_r(alt)
|
||||
else: msg_r(s)
|
||||
def vmsg(s,force=False):
|
||||
if opt.verbose or force: msg(s)
|
||||
def vmsg_r(s,force=False):
|
||||
if opt.verbose or force: msg_r(s)
|
||||
def Vmsg(s,force=False):
|
||||
if opt.verbose or force: Msg(s)
|
||||
def Vmsg_r(s,force=False):
|
||||
if opt.verbose or force: Msg_r(s)
|
||||
def dmsg(s):
|
||||
if opt.debug: msg(s)
|
||||
|
||||
def suf(arg,suf_type='s',verb='none'):
|
||||
suf_types = {
|
||||
'none': {
|
||||
|
|
@ -449,6 +446,7 @@ def compare_or_die(val1, desc1, val2, desc2, e='Error'):
|
|||
def check_wallet_extension(fn):
|
||||
from .wallet import Wallet
|
||||
if not Wallet.ext_to_type(get_extension(fn)):
|
||||
from .exception import BadFileExtension
|
||||
raise BadFileExtension(f'{fn!r}: unrecognized seed source file extension')
|
||||
|
||||
def make_full_path(outdir,outfile):
|
||||
|
|
@ -460,6 +458,7 @@ def confirm_or_raise(message,q,expect='YES',exit_msg='Exiting at user request'):
|
|||
a = f'{q} ' if q[0].isupper() else f'Are you sure you want to {q}?\n'
|
||||
b = f'Type uppercase {expect!r} to confirm: '
|
||||
if line_input(a+b).strip() != expect:
|
||||
from .exception import UserNonConfirmation
|
||||
raise UserNonConfirmation(exit_msg)
|
||||
|
||||
def get_words_from_user(prompt):
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
xmrseed.py: Monero mnemonic conversion class for the MMGen suite
|
||||
"""
|
||||
|
||||
from .exception import *
|
||||
from .baseconv import baseconv
|
||||
from .util import die
|
||||
|
||||
|
|
@ -55,6 +54,8 @@ class xmrseed(baseconv):
|
|||
wl = self.digits
|
||||
base = len(wl)
|
||||
|
||||
from .exception import MnemonicError
|
||||
|
||||
if not set(words) <= set(wl):
|
||||
raise MnemonicError( f'{words!r}: not in {desc} format' )
|
||||
|
||||
|
|
@ -64,6 +65,7 @@ class xmrseed(baseconv):
|
|||
z = self.monero_mn_checksum(words[:-1])
|
||||
if z != words[-1]:
|
||||
raise MnemonicError(f'invalid {desc} checksum')
|
||||
|
||||
words = tuple(words[:-1])
|
||||
|
||||
def gen():
|
||||
|
|
@ -82,6 +84,7 @@ class xmrseed(baseconv):
|
|||
base = len(wl)
|
||||
|
||||
if len(bytestr) not in self.seedlen_map:
|
||||
from .exception import SeedLengthError
|
||||
raise SeedLengthError(f'{len(bytestr)}: invalid seed byte length for {desc}')
|
||||
|
||||
def num2base_monero(num):
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
|
|||
|
||||
# Import these _after_ local path's been added to sys.path
|
||||
from test.objattrtest_py_d.oat_common import *
|
||||
from mmgen.common import *
|
||||
from mmgen.addrlist import *
|
||||
from mmgen.passwdlist import *
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue