import cleanups throughout

This commit is contained in:
The MMGen Project 2022-01-22 14:26:13 +00:00
commit ad569cbeb7
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
18 changed files with 98 additions and 61 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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':

View file

@ -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,

View file

@ -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

View file

@ -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():

View file

@ -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

View file

@ -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']

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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):

View file

@ -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):

View file

@ -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 *