Browse Source

whitespace, cleanups, minor fixes

The MMGen Project 3 years ago
parent
commit
0138a6fa49

+ 0 - 7
mmgen/addr.py

@@ -279,10 +279,3 @@ class KeyGeneratorDummy(KeyGenerator):
 		return PubKey(
 		return PubKey(
 			s       = privhex,
 			s       = privhex,
 			privkey = privhex )
 			privkey = privhex )
-
-def is_bip39_str(s):
-	from .bip39 import bip39
-	return bool(bip39.tohex(s.split(),wl_id='bip39'))
-
-def is_xmrseed(s):
-	return bool(baseconv.tobytes(s.split(),wl_id='xmrseed'))

+ 2 - 2
mmgen/addrfile.py

@@ -57,10 +57,10 @@ class AddrFile(MMGenObject):
 		self.infile = None
 		self.infile = None
 
 
 	def encrypt(self,desc='new key list'):
 	def encrypt(self,desc='new key list'):
-		from .crypto import mmgen_encrypt
+		from .crypto import mmgen_encrypt,mmenc_ext
 		from .globalvars import g
 		from .globalvars import g
 		self.fmt_data = mmgen_encrypt(self.fmt_data.encode(),desc,'')
 		self.fmt_data = mmgen_encrypt(self.fmt_data.encode(),desc,'')
-		self.ext += f'.{g.mmenc_ext}'
+		self.ext += f'.{mmenc_ext}'
 
 
 	@property
 	@property
 	def filename(self):
 	def filename(self):

+ 3 - 0
mmgen/altcoins/eth/tw.py

@@ -166,6 +166,7 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet):
 			assert token_addr == None,'EthereumTokenTrackingWallet_chk1'
 			assert token_addr == None,'EthereumTokenTrackingWallet_chk1'
 			token_addr = await self.sym2addr(proto.tokensym) # returns None on failure
 			token_addr = await self.sym2addr(proto.tokensym) # returns None on failure
 			if not is_coin_addr(proto,token_addr):
 			if not is_coin_addr(proto,token_addr):
+				from mmgen.exception import UnrecognizedTokenSymbol
 				raise UnrecognizedTokenSymbol(f'Specified token {proto.tokensym!r} could not be resolved!')
 				raise UnrecognizedTokenSymbol(f'Specified token {proto.tokensym!r} could not be resolved!')
 
 
 		from mmgen.obj import TokenAddr
 		from mmgen.obj import TokenAddr
@@ -246,7 +247,9 @@ Actions:         [q]uit view, [p]rint to file, pager [v]iew, [w]ide view,
 		'l':'a_lbl_add','D':'a_addr_delete','R':'a_balance_refresh' }
 		'l':'a_lbl_add','D':'a_addr_delete','R':'a_balance_refresh' }
 
 
 	async def __init__(self,proto,*args,**kwargs):
 	async def __init__(self,proto,*args,**kwargs):
+		from mmgen.globalvars import g
 		if g.cached_balances:
 		if g.cached_balances:
+			from mmgen.color import yellow
 			self.hdr_fmt += '\n' + yellow('WARNING: Using cached balances. These may be out of date!')
 			self.hdr_fmt += '\n' + yellow('WARNING: Using cached balances. These may be out of date!')
 		await TwUnspentOutputs.__init__(self,proto,*args,**kwargs)
 		await TwUnspentOutputs.__init__(self,proto,*args,**kwargs)
 
 

+ 2 - 0
mmgen/altcoins/eth/tx.py

@@ -27,6 +27,7 @@ from mmgen.obj import *
 
 
 from mmgen.tx import MMGenTX
 from mmgen.tx import MMGenTX
 from mmgen.tw import TrackingWallet
 from mmgen.tw import TrackingWallet
+
 from .contract import Token
 from .contract import Token
 from .obj import ETHAmt,ETHNonce
 from .obj import ETHAmt,ETHNonce
 
 
@@ -268,6 +269,7 @@ class EthereumMMGenTX:
 					\n""".replace('\t','')
 					\n""".replace('\t','')
 			t = self.txobj
 			t = self.txobj
 			td = t['data']
 			td = t['data']
+			from mmgen.color import yellow
 			return fs.format(
 			return fs.format(
 				*((t[k] if t[k] != '' else Str('None')).hl() for k in self.fmt_keys),
 				*((t[k] if t[k] != '' else Str('None')).hl() for k in self.fmt_keys),
 				d      = '{}... ({} bytes)'.format(td[:40],len(td)//2) if len(td) else Str('None'),
 				d      = '{}... ({} bytes)'.format(td[:40],len(td)//2) if len(td) else Str('None'),

+ 0 - 3
mmgen/amt.py

@@ -168,9 +168,6 @@ class BTCAmt(CoinAmt):
 class BCHAmt(BTCAmt):
 class BCHAmt(BTCAmt):
 	pass
 	pass
 
 
-class B2XAmt(BTCAmt):
-	pass
-
 class LTCAmt(BTCAmt):
 class LTCAmt(BTCAmt):
 	max_amt = 84000000
 	max_amt = 84000000
 
 

+ 8 - 2
mmgen/baseconv.py

@@ -24,8 +24,14 @@ from hashlib import sha256
 from .exception import *
 from .exception import *
 from .util import die
 from .util import die
 
 
-def is_b58_str(s): return set(list(s)) <= set(baseconv.digits['b58'])
-def is_b32_str(s): return set(list(s)) <= set(baseconv.digits['b32'])
+def is_b58_str(s):
+	return set(list(s)) <= set(baseconv.digits['b58'])
+
+def is_b32_str(s):
+	return set(list(s)) <= set(baseconv.digits['b32'])
+
+def is_xmrseed(s):
+	return bool(baseconv.tobytes(s.split(),wl_id='xmrseed'))
 
 
 class baseconv(object):
 class baseconv(object):
 
 

+ 0 - 1
mmgen/bech32.py

@@ -8,7 +8,6 @@
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 #
 #
 # Unaltered except for the following changes by the MMGen Project:
 # Unaltered except for the following changes by the MMGen Project:
-#   'python3' changed to 'python' in the hashbang
 #   leading spaces converted to tabs
 #   leading spaces converted to tabs
 #
 #
 """Reference implementation for Bech32 and segwit addresses."""
 """Reference implementation for Bech32 and segwit addresses."""

+ 11 - 0
mmgen/bip39.py

@@ -2109,6 +2109,14 @@ zoo
 		except:
 		except:
 			raise ValueError(f'{seed_bits!r}: invalid seed length for BIP39 mnemonic')
 			raise ValueError(f'{seed_bits!r}: invalid seed length for BIP39 mnemonic')
 
 
+	@classmethod
+	def tobytes(cls,*args,**kwargs):
+		raise NotImplementedError('Method not supported')
+
+	@classmethod
+	def frombytes(cls,*args,**kwargs):
+		raise NotImplementedError('Method not supported')
+
 	@classmethod
 	@classmethod
 	def tohex(cls,words,wl_id,pad=None):
 	def tohex(cls,words,wl_id,pad=None):
 		assert isinstance(words,(list,tuple)),'words must be list or tuple'
 		assert isinstance(words,(list,tuple)),'words must be list or tuple'
@@ -2175,3 +2183,6 @@ zoo
 	@classmethod
 	@classmethod
 	def init_mn(cls,mn_id):
 	def init_mn(cls,mn_id):
 		assert mn_id == 'bip39', "'mn_id' must be 'bip39'"
 		assert mn_id == 'bip39', "'mn_id' must be 'bip39'"
+
+def is_bip39_str(s):
+	return bool(bip39.tohex(s.split(),wl_id='bip39'))

+ 2 - 0
mmgen/crypto.py

@@ -25,6 +25,8 @@ from cryptography.hazmat.backends import default_backend
 from hashlib import sha256
 from hashlib import sha256
 from .common import *
 from .common import *
 
 
+mmenc_ext = 'mmenc'
+
 def sha256_rounds(s,n):
 def sha256_rounds(s,n):
 	for i in range(n):
 	for i in range(n):
 		s = sha256(s).digest()
 		s = sha256(s).digest()

+ 0 - 1
mmgen/globalvars.py

@@ -266,7 +266,6 @@ class GlobalContext(Lockable):
 	scramble_hash_rounds = 10
 	scramble_hash_rounds = 10
 	subseeds = 100
 	subseeds = 100
 
 
-	mmenc_ext      = 'mmenc'
 	salt_len       = 16
 	salt_len       = 16
 	aesctr_iv_len  = 16
 	aesctr_iv_len  = 16
 	aesctr_dfl_iv  = int.to_bytes(1,aesctr_iv_len,'big')
 	aesctr_dfl_iv  = int.to_bytes(1,aesctr_iv_len,'big')

+ 1 - 1
mmgen/help.py

@@ -20,7 +20,7 @@
 help.py:  help notes for MMGen suite commands
 help.py:  help notes for MMGen suite commands
 """
 """
 
 
-def help_notes_func(proto,k):
+def help_notes_func(proto,po,k):
 	from .globalvars import g
 	from .globalvars import g
 
 
 	def fee_spec_letters(use_quotes=False):
 	def fee_spec_letters(use_quotes=False):

+ 2 - 1
mmgen/main_addrgen.py

@@ -139,7 +139,8 @@ addr_type = MMGenAddrType(
 	id_str = opt.type or proto.dfl_mmtype,
 	id_str = opt.type or proto.dfl_mmtype,
 	errmsg = errmsg )
 	errmsg = errmsg )
 
 
-if len(cmd_args) < 1: opts.usage()
+if len(cmd_args) < 1:
+	opts.usage()
 
 
 if getattr(opt,'use_old_ed25519',False):
 if getattr(opt,'use_old_ed25519',False):
 	msg('Using old (slow) ed25519 module by user request')
 	msg('Using old (slow) ed25519 module by user request')

+ 35 - 13
mmgen/obj.py

@@ -57,11 +57,18 @@ def get_obj(objname,*args,**kwargs):
 	else:
 	else:
 		return True if return_bool else ret
 		return True if return_bool else ret
 
 
-def is_addr_idx(s):        return get_obj(AddrIdx,    n=s,   silent=True,return_bool=True)
-def is_addrlist_id(s):     return get_obj(AddrListID, sid=s, silent=True,return_bool=True)
+def is_addr_idx(s):
+	return get_obj(AddrIdx, n=s, silent=True, return_bool=True)
+
+def is_addrlist_id(s):
+	return get_obj(AddrListID, sid=s, silent=True, return_bool=True)
+
+def is_mmgen_id(proto,s):
+	return get_obj(MMGenID, proto=proto, id_str=s, silent=True, return_bool=True)
+
+def is_coin_addr(proto,s):
+	return get_obj(CoinAddr, proto=proto, addr=s, silent=True, return_bool=True)
 
 
-def is_mmgen_id(proto,s):  return get_obj(MMGenID,  proto=proto, id_str=s, silent=True,return_bool=True)
-def is_coin_addr(proto,s): return get_obj(CoinAddr, proto=proto, addr=s,   silent=True,return_bool=True)
 # dict that keeps a list of keys for efficient lookup by index
 # dict that keeps a list of keys for efficient lookup by index
 class IndexedDict(dict):
 class IndexedDict(dict):
 
 
@@ -92,9 +99,14 @@ class IndexedDict(dict):
 	def die(self,desc):
 	def die(self,desc):
 		raise NotImplementedError(f'{desc} not implemented for type {type(self).__name__}')
 		raise NotImplementedError(f'{desc} not implemented for type {type(self).__name__}')
 
 
-class MMGenList(list,MMGenObject): pass
-class MMGenDict(dict,MMGenObject): pass
-class Str(str,Hilite): pass
+class MMGenList(list,MMGenObject):
+	pass
+
+class MMGenDict(dict,MMGenObject):
+	pass
+
+class Str(str,Hilite):
+	pass
 
 
 class Int(int,Hilite,InitErrors):
 class Int(int,Hilite,InitErrors):
 	min_val = None
 	min_val = None
@@ -253,8 +265,11 @@ class MMGenListItem(MMGenObject):
 	def _asdict(self):
 	def _asdict(self):
 		return dict((k,v) for k,v in self.__dict__.items() if k in self.valid_attrs)
 		return dict((k,v) for k,v in self.__dict__.items() if k in self.valid_attrs)
 
 
-class MMGenIdx(Int): min_val = 1
-class AddrIdx(MMGenIdx): max_digits = 7
+class MMGenIdx(Int):
+	min_val = 1
+
+class AddrIdx(MMGenIdx):
+	max_digits = 7
 
 
 class MMGenRange(tuple,InitErrors,MMGenObject):
 class MMGenRange(tuple,InitErrors,MMGenObject):
 
 
@@ -428,10 +443,17 @@ class HexStr(str,Hilite,InitErrors):
 		except Exception as e:
 		except Exception as e:
 			return cls.init_fail(e,s)
 			return cls.init_fail(e,s)
 
 
-class CoinTxID(HexStr):       color,width,hexcase = 'purple',64,'lower'
-class WalletPassword(HexStr): color,width,hexcase = 'blue',32,'lower'
-class MoneroViewKey(HexStr):  color,width,hexcase = 'cyan',64,'lower' # FIXME - no checking performed
-class MMGenTxID(HexStr):      color,width,hexcase = 'red',6,'upper'
+class CoinTxID(HexStr):
+	color,width,hexcase = ('purple',64,'lower')
+
+class WalletPassword(HexStr):
+	color,width,hexcase = ('blue',32,'lower')
+
+class MoneroViewKey(HexStr):
+	color,width,hexcase = ('cyan',64,'lower') # FIXME - no checking performed
+
+class MMGenTxID(HexStr):
+	color,width,hexcase = ('red',6,'upper')
 
 
 class AddrListID(str,Hilite,InitErrors,MMGenObject):
 class AddrListID(str,Hilite,InitErrors,MMGenObject):
 	width = 10
 	width = 10

+ 11 - 5
mmgen/passwdlist.py

@@ -25,9 +25,10 @@ from collections import namedtuple
 from .exception import InvalidPasswdFormat
 from .exception import InvalidPasswdFormat
 from .util import ymsg,is_hex_str,is_int,keypress_confirm
 from .util import ymsg,is_hex_str,is_int,keypress_confirm
 from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
 from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString
-from .baseconv import baseconv,is_b32_str,is_b58_str
+from .baseconv import baseconv,is_b32_str,is_b58_str,is_xmrseed
+from .bip39 import is_bip39_str
 from .key import PrivKey
 from .key import PrivKey
-from .addr import MMGenPasswordType,AddrIdx,AddrListID,is_xmrseed,is_bip39_str
+from .addr import MMGenPasswordType,AddrIdx,AddrListID
 from .addrlist import (
 from .addrlist import (
 	AddrListChksum,
 	AddrListChksum,
 	AddrListIDStr,
 	AddrListIDStr,
@@ -197,13 +198,18 @@ class PasswordList(AddrList):
 		elif self.pw_fmt == 'xmrseed':
 		elif self.pw_fmt == 'xmrseed':
 			pw_len_hex = baseconv.seedlen_map_rev['xmrseed'][self.pw_len] * 2
 			pw_len_hex = baseconv.seedlen_map_rev['xmrseed'][self.pw_len] * 2
 			# take most significant part
 			# take most significant part
-			bytes_trunc = bytes.fromhex(hex_sec[:pw_len_hex])
 			from .protocol import init_proto
 			from .protocol import init_proto
-			bytes_preproc = init_proto('xmr').preprocess_key(bytes_trunc,None)
+			bytes_preproc = init_proto('xmr').preprocess_key(
+				bytes.fromhex(hex_sec[:pw_len_hex]),
+				None )
 			return ' '.join(baseconv.frombytes(bytes_preproc,wl_id='xmrseed'))
 			return ' '.join(baseconv.frombytes(bytes_preproc,wl_id='xmrseed'))
 		else:
 		else:
 			# take least significant part
 			# take least significant part
-			return baseconv.fromhex(hex_sec,self.pw_fmt,pad=self.pw_len,tostr=True)[-self.pw_len:]
+			return baseconv.fromhex(
+				hex_sec,
+				self.pw_fmt,
+				pad = self.pw_len,
+				tostr = True )[-self.pw_len:]
 
 
 	def check_format(self,pw):
 	def check_format(self,pw):
 		if not self.pw_info[self.pw_fmt].chk_func(pw):
 		if not self.pw_info[self.pw_fmt].chk_func(pw):

+ 15 - 23
mmgen/protocol.py

@@ -27,7 +27,7 @@ from .util import msg,ymsg,Msg,ydie
 from .devtools import *
 from .devtools import *
 from .obj import CoinAddr,MMGenAddrType
 from .obj import CoinAddr,MMGenAddrType
 from .globalvars import g
 from .globalvars import g
-from .amt import BTCAmt,LTCAmt,BCHAmt,B2XAmt,XMRAmt
+from .amt import BTCAmt,LTCAmt,BCHAmt,XMRAmt
 from .altcoins.eth.obj import ETHAmt
 from .altcoins.eth.obj import ETHAmt
 import mmgen.bech32 as bech32
 import mmgen.bech32 as bech32
 
 
@@ -52,13 +52,13 @@ _b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 # The 'zero address':
 # The 'zero address':
 # 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
 # 1111111111111111111114oLvT2 (pubkeyhash = '\0'*20)
 
 
-def _b58chk_encode(bstr):
-	lzeroes = len(bstr) - len(bstr.lstrip(b'\x00'))
+def _b58chk_encode(in_bytes):
+	lzeroes = len(in_bytes) - len(in_bytes.lstrip(b'\x00'))
 	def do_enc(n):
 	def do_enc(n):
 		while n:
 		while n:
 			yield _b58a[n % 58]
 			yield _b58a[n % 58]
 			n //= 58
 			n //= 58
-	return ('1' * lzeroes) + ''.join(do_enc(int.from_bytes(bstr+hash256bytes(bstr)[:4],'big')))[::-1]
+	return ('1' * lzeroes) + ''.join(do_enc(int.from_bytes(in_bytes+hash256bytes(in_bytes)[:4],'big')))[::-1]
 
 
 def _b58chk_decode(s):
 def _b58chk_decode(s):
 	lzeroes = len(s) - len(s.lstrip('1'))
 	lzeroes = len(s) - len(s.lstrip('1'))
@@ -177,9 +177,11 @@ class CoinProtocol(MMGenObject):
 			return False
 			return False
 
 
 		def coin_addr(self,addr):
 		def coin_addr(self,addr):
+			from .addr import CoinAddr
 			return CoinAddr( proto=self, addr=addr )
 			return CoinAddr( proto=self, addr=addr )
 
 
 		def addr_type(self,id_str):
 		def addr_type(self,id_str):
+			from .addr import MMGenAddrType
 			return MMGenAddrType( proto=self, id_str=id_str )
 			return MMGenAddrType( proto=self, id_str=id_str )
 
 
 	class Secp256k1(Base):
 	class Secp256k1(Base):
@@ -221,7 +223,6 @@ class CoinProtocol(MMGenObject):
 		block0          = '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
 		block0          = '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
 		forks           = [
 		forks           = [
 			_finfo(478559,'00000000000000000019f112ec0a9982926f1258cdcc558dd7c3b7e5dc7fa148','BCH',False),
 			_finfo(478559,'00000000000000000019f112ec0a9982926f1258cdcc558dd7c3b7e5dc7fa148','BCH',False),
-			_finfo(None,'','B2X',True),
 		]
 		]
 		caps            = ('rbf','segwit')
 		caps            = ('rbf','segwit')
 		mmcaps          = ('key','addr','rpc','tx')
 		mmcaps          = ('key','addr','rpc','tx')
@@ -288,8 +289,9 @@ class CoinProtocol(MMGenObject):
 
 
 		def pubhash2addr(self,pubkey_hash,p2sh):
 		def pubhash2addr(self,pubkey_hash,p2sh):
 			assert len(pubkey_hash) == 40, f'{len(pubkey_hash)}: invalid length for pubkey hash'
 			assert len(pubkey_hash) == 40, f'{len(pubkey_hash)}: invalid length for pubkey hash'
-			s = self.addr_fmt_to_ver_bytes(('p2pkh','p2sh')[p2sh],return_hex=True) + pubkey_hash
-			return _b58chk_encode(bytes.fromhex(s))
+			return _b58chk_encode(bytes.fromhex(
+				self.addr_fmt_to_ver_bytes(('p2pkh','p2sh')[p2sh],return_hex=True) + pubkey_hash
+			))
 
 
 		# Segwit:
 		# Segwit:
 		def pubhex2redeem_script(self,pubhex):
 		def pubhex2redeem_script(self,pubhex):
@@ -299,7 +301,8 @@ class CoinProtocol(MMGenObject):
 			return self.witness_vernum_hex + '14' + hash160(pubhex)
 			return self.witness_vernum_hex + '14' + hash160(pubhex)
 
 
 		def pubhex2segwitaddr(self,pubhex):
 		def pubhex2segwitaddr(self,pubhex):
-			return self.pubhash2addr(hash160(self.pubhex2redeem_script(pubhex)),p2sh=True)
+			return self.pubhash2addr(
+				hash160( self.pubhex2redeem_script(pubhex)), p2sh=True )
 
 
 		def pubhash2bech32addr(self,pubhash):
 		def pubhash2bech32addr(self,pubhash):
 			d = list(bytes.fromhex(pubhash))
 			d = list(bytes.fromhex(pubhash))
@@ -336,19 +339,6 @@ class CoinProtocol(MMGenObject):
 	class BitcoinCashRegtest(BitcoinCashTestnet):
 	class BitcoinCashRegtest(BitcoinCashTestnet):
 		halving_interval = 150
 		halving_interval = 150
 
 
-	class B2X(Bitcoin):
-		is_fork_of      = 'Bitcoin'
-		coin_amt        = B2XAmt
-		max_tx_fee      = B2XAmt('0.1')
-		forks = [
-			_finfo(None,'','BTC',True) # activation: 494784
-		]
-		ignore_daemon_version = False
-
-	class B2XTestnet(B2X):
-		addr_ver_bytes     = { '6f': 'p2pkh', 'c4': 'p2sh' }
-		wif_ver_num        = { 'std': 'ef' }
-
 	class Litecoin(Bitcoin):
 	class Litecoin(Bitcoin):
 		block0          = '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2'
 		block0          = '12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2'
 		addr_ver_bytes  = { '30': 'p2pkh', '32': 'p2sh', '05': 'p2sh' } # new p2sh ver 0x32 must come first
 		addr_ver_bytes  = { '30': 'p2pkh', '32': 'p2sh', '05': 'p2sh' } # new p2sh ver 0x32 must come first
@@ -508,8 +498,10 @@ class CoinProtocol(MMGenObject):
 
 
 		def preprocess_key(self,sec,pubkey_type): # reduce key
 		def preprocess_key(self,sec,pubkey_type): # reduce key
 			from .ed25519 import l
 			from .ed25519 import l
-			n = int.from_bytes(sec[::-1],'big') % l
-			return int.to_bytes(n,self.privkey_len,'big')[::-1]
+			return int.to_bytes(
+				int.from_bytes( sec[::-1], 'big' ) % l,
+				self.privkey_len,
+				'big' )[::-1]
 
 
 		def parse_addr(self,addr):
 		def parse_addr(self,addr):
 
 

+ 1 - 1
mmgen/seed.py

@@ -23,7 +23,6 @@ seed.py:  Seed-related classes and methods for the MMGen suite
 from .common import *
 from .common import *
 from .objmethods import Hilite,InitErrors
 from .objmethods import Hilite,InitErrors
 from .obj import ImmutableAttr,get_obj
 from .obj import ImmutableAttr,get_obj
-from .crypto import get_random,scramble_seed
 
 
 class SeedID(str,Hilite,InitErrors):
 class SeedID(str,Hilite,InitErrors):
 	color = 'blue'
 	color = 'blue'
@@ -54,6 +53,7 @@ class SeedBase(MMGenObject):
 
 
 	def __init__(self,seed_bin=None):
 	def __init__(self,seed_bin=None):
 		if not seed_bin:
 		if not seed_bin:
+			from .crypto import get_random
 			# Truncate random data for smaller seed lengths
 			# Truncate random data for smaller seed lengths
 			seed_bin = sha256(get_random(1033)).digest()[:(opt.seed_len or g.dfl_seed_len)//8]
 			seed_bin = sha256(get_random(1033)).digest()[:(opt.seed_len or g.dfl_seed_len)//8]
 		elif len(seed_bin)*8 not in g.seed_lens:
 		elif len(seed_bin)*8 not in g.seed_lens:

+ 1 - 1
mmgen/share/Opts.py

@@ -67,7 +67,7 @@ def print_help(proto,po,opts_data,opt_filter):
 
 
 	from mmgen.help import help_notes_func
 	from mmgen.help import help_notes_func
 	def help_notes(k):
 	def help_notes(k):
-		return help_notes_func(proto,k)
+		return help_notes_func(proto,po,k)
 
 
 	def gen_arg_tuple(func,text):
 	def gen_arg_tuple(func,text):
 		d = {'proto': proto,'help_notes':help_notes}
 		d = {'proto': proto,'help_notes':help_notes}

+ 8 - 6
mmgen/tool.py

@@ -22,7 +22,7 @@ tool.py:  Routines for the 'mmgen-tool' utility
 
 
 from .protocol import hash160
 from .protocol import hash160
 from .common import *
 from .common import *
-from .crypto import *
+from .crypto import get_random
 from .key import PrivKey
 from .key import PrivKey
 from .seedsplit import MasterShareIdx
 from .seedsplit import MasterShareIdx
 from .addr import *
 from .addr import *
@@ -506,9 +506,9 @@ class MMGenToolCmdCoin(MMGenToolCmds):
 		pubhex = gd.kg.to_pubhex(PrivKey(
 		pubhex = gd.kg.to_pubhex(PrivKey(
 			self.proto,
 			self.proto,
 			wif = wifkey ))
 			wif = wifkey ))
-		addr = gd.ag.to_addr(pubhex)
-		rs = gd.ag.to_segwit_redeem_script(pubhex)
-		return (rs,addr)
+		return (
+			gd.ag.to_segwit_redeem_script(pubhex),
+			gd.ag.to_addr(pubhex) )
 
 
 	def privhex2addr(self,privhex:'sstr',output_pubhex=False):
 	def privhex2addr(self,privhex:'sstr',output_pubhex=False):
 		"generate coin address from raw private key data in hexadecimal format"
 		"generate coin address from raw private key data in hexadecimal format"
@@ -742,22 +742,24 @@ class MMGenToolCmdFileCrypt(MMGenToolCmds):
 	def encrypt(self,infile:str,outfile='',hash_preset=''):
 	def encrypt(self,infile:str,outfile='',hash_preset=''):
 		"encrypt a file"
 		"encrypt a file"
 		data = get_data_from_file(infile,'data for encryption',binary=True)
 		data = get_data_from_file(infile,'data for encryption',binary=True)
+		from .crypto import mmgen_encrypt,mmenc_ext
 		enc_d = mmgen_encrypt(data,'user data',hash_preset)
 		enc_d = mmgen_encrypt(data,'user data',hash_preset)
 		if not outfile:
 		if not outfile:
-			outfile = f'{os.path.basename(infile)}.{g.mmenc_ext}'
+			outfile = f'{os.path.basename(infile)}.{mmenc_ext}'
 		write_data_to_file(outfile,enc_d,'encrypted data',binary=True)
 		write_data_to_file(outfile,enc_d,'encrypted data',binary=True)
 		return True
 		return True
 
 
 	def decrypt(self,infile:str,outfile='',hash_preset=''):
 	def decrypt(self,infile:str,outfile='',hash_preset=''):
 		"decrypt a file"
 		"decrypt a file"
 		enc_d = get_data_from_file(infile,'encrypted data',binary=True)
 		enc_d = get_data_from_file(infile,'encrypted data',binary=True)
+		from .crypto import mmgen_decrypt,mmenc_ext
 		while True:
 		while True:
 			dec_d = mmgen_decrypt(enc_d,'user data',hash_preset)
 			dec_d = mmgen_decrypt(enc_d,'user data',hash_preset)
 			if dec_d: break
 			if dec_d: break
 			msg('Trying again...')
 			msg('Trying again...')
 		if not outfile:
 		if not outfile:
 			o = os.path.basename(infile)
 			o = os.path.basename(infile)
-			outfile = remove_extension(o,g.mmenc_ext)
+			outfile = remove_extension(o,mmenc_ext)
 			if outfile == o: outfile += '.dec'
 			if outfile == o: outfile += '.dec'
 		write_data_to_file(outfile,dec_d,'decrypted data',binary=True)
 		write_data_to_file(outfile,dec_d,'decrypted data',binary=True)
 		return True
 		return True

+ 28 - 8
mmgen/tw.py

@@ -20,21 +20,37 @@
 tw: Tracking wallet methods for the MMGen suite
 tw: Tracking wallet methods for the MMGen suite
 """
 """
 
 
-import json
+import os,json,time
 from collections import namedtuple
 from collections import namedtuple
-from .exception import *
-from .common import *
+from string import ascii_letters,digits
+
+from .globalvars import g
+from .color import red,yellow,green
+from .exception import BadTwLabel,BadTwComment,BadAgeFormat,WalletFileError
+from .util import (
+	msg,
+	msg_r,
+	dmsg,
+	die,
+	capfirst,
+	suf,
+	fmt,
+	make_timestr,
+	check_or_create_dir,
+	keypress_confirm,
+	write_data_to_file,
+	get_data_from_file,
+	line_input,
+	do_pager,
+	write_mode,
+	altcoin_subclass
+)
 from .base_obj import AsyncInit
 from .base_obj import AsyncInit
 from .objmethods import Hilite,InitErrors,MMGenObject
 from .objmethods import Hilite,InitErrors,MMGenObject
 from .obj import *
 from .obj import *
 from .tx import is_mmgen_id,is_coin_addr
 from .tx import is_mmgen_id,is_coin_addr
 from .rpc import rpc_init
 from .rpc import rpc_init
 
 
-CUR_HOME,ERASE_ALL = '\033[H','\033[0J'
-
-def CUR_RIGHT(n):
-	return f'\033[{n}C'
-
 def get_tw_label(proto,s):
 def get_tw_label(proto,s):
 	"""
 	"""
 	raise an exception on a malformed comment, return None on an empty or invalid label
 	raise an exception on a malformed comment, return None on an empty or invalid label
@@ -442,6 +458,10 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
 		from .term import get_char
 		from .term import get_char
 		prompt = self.prompt.strip() + '\b'
 		prompt = self.prompt.strip() + '\b'
 		no_output,oneshot_msg = False,None
 		no_output,oneshot_msg = False,None
+		from .opts import opt
+		CUR_HOME,ERASE_ALL = '\033[H','\033[0J'
+		CUR_RIGHT = lambda n: f'\033[{n}C'
+
 		while True:
 		while True:
 			msg_r('' if no_output else '\n\n' if opt.no_blank else CUR_HOME+ERASE_ALL)
 			msg_r('' if no_output else '\n\n' if opt.no_blank else CUR_HOME+ERASE_ALL)
 			reply = get_char(
 			reply = get_char(

+ 2 - 1
mmgen/util.py

@@ -713,7 +713,8 @@ def get_words(infile,desc,prompt):
 
 
 def mmgen_decrypt_file_maybe(fn,desc='',quiet=False,silent=False):
 def mmgen_decrypt_file_maybe(fn,desc='',quiet=False,silent=False):
 	d = get_data_from_file(fn,desc,binary=True,quiet=quiet,silent=silent)
 	d = get_data_from_file(fn,desc,binary=True,quiet=quiet,silent=silent)
-	have_enc_ext = get_extension(fn) == g.mmenc_ext
+	from .crypto import mmenc_ext
+	have_enc_ext = get_extension(fn) == mmenc_ext
 	if have_enc_ext or not is_utf8(d):
 	if have_enc_ext or not is_utf8(d):
 		m = ('Attempting to decrypt','Decrypting')[have_enc_ext]
 		m = ('Attempting to decrypt','Decrypting')[have_enc_ext]
 		qmsg(f'{m} {desc} {fn!r}')
 		qmsg(f'{m} {desc} {fn!r}')

+ 1 - 1
test/gentest.py

@@ -334,7 +334,7 @@ def speed_test(kg,ag,rounds):
 	qmsg(
 	qmsg(
 		f'\rRound {i+1}/{rounds} ' +
 		f'\rRound {i+1}/{rounds} ' +
 		f'\n{rounds} addresses generated' +
 		f'\n{rounds} addresses generated' +
-		('' if g.test_suite_deterministic else ' in {time.time()-start:.2f} seconds')
+		('' if g.test_suite_deterministic else f' in {time.time()-start:.2f} seconds')
 	)
 	)
 
 
 def dump_test(kg,ag,fh):
 def dump_test(kg,ag,fh):

+ 5 - 7
test/misc/opts.py

@@ -16,11 +16,11 @@ opts_data = {
 -E, --fee-estimate-mode=M Specify the network fee estimate mode.
 -E, --fee-estimate-mode=M Specify the network fee estimate mode.
 -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
 -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
                       'f' at offset 'o' (comma-separated)
                       'f' at offset 'o' (comma-separated)
--K, --key-generator=m Use method 'm' for public key generation
-                      Options: {kgs} (default: {kg})
+-k, --keep-label      Reuse label of input wallet for output wallet
 -l, --seed-len=    l  Specify wallet seed length of 'l' bits.
 -l, --seed-len=    l  Specify wallet seed length of 'l' bits.
 -L, --label=       l  Specify a label 'l' for output wallet
 -L, --label=       l  Specify a label 'l' for output wallet
--m, --keep-label      Reuse label of input wallet for output wallet
+-m, --minconf=     n  Minimum number of confirmations required to spend
+                      outputs (default: 1)
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -u, --subseeds=    n  The number of subseed pairs to scan for
 -u, --subseeds=    n  The number of subseed pairs to scan for
@@ -35,8 +35,6 @@ opts_data = {
 	},
 	},
 	'code': {
 	'code': {
 		'options': lambda s: s.format(
 		'options': lambda s: s.format(
-			kgs=' '.join([f'{n}:{k}' for n,k in enumerate(g.key_generators,1)]),
-			kg=g.key_generator,
 			g=g,
 			g=g,
 		),
 		),
 		'notes': lambda s: s.format(nn='a note'),
 		'notes': lambda s: s.format(nn='a note'),
@@ -58,7 +56,7 @@ for k in (
 	'passwd_file',       # infile_opts - check_infile()
 	'passwd_file',       # infile_opts - check_infile()
 	'outdir',            # check_outdir()
 	'outdir',            # check_outdir()
 	'subseeds',          # opt_sets_global
 	'subseeds',          # opt_sets_global
-	'key_generator',     # global_sets_opt
+	'minconf',           # global_sets_opt
 	'hidden_incog_input_params',
 	'hidden_incog_input_params',
 	):
 	):
 	msg('{:30} {}'.format( f'opt.{k}:', getattr(opt,k) ))
 	msg('{:30} {}'.format( f'opt.{k}:', getattr(opt,k) ))
@@ -66,6 +64,6 @@ for k in (
 msg('')
 msg('')
 for k in (
 for k in (
 	'subseeds',          # opt_sets_global
 	'subseeds',          # opt_sets_global
-	'key_generator',     # global_sets_opt
+	'minconf',           # global_sets_opt
 	):
 	):
 	msg('{:30} {}'.format( f'g.{k}:', getattr(opt,k) ))
 	msg('{:30} {}'.format( f'g.{k}:', getattr(opt,k) ))

+ 1 - 0
test/overlay/fakemods/tw.py

@@ -25,6 +25,7 @@ if os.getenv('MMGEN_BOGUS_WALLET_DATA'):
 			o.date = 1831006505 - int(9.7 * 60 * (o.confs - 1))
 			o.date = 1831006505 - int(9.7 * 60 * (o.confs - 1))
 
 
 	async def fake_get_unspent_rpc(foo):
 	async def fake_get_unspent_rpc(foo):
+		from decimal import Decimal
 		return json.loads(get_data_from_file(os.getenv('MMGEN_BOGUS_WALLET_DATA')),parse_float=Decimal)
 		return json.loads(get_data_from_file(os.getenv('MMGEN_BOGUS_WALLET_DATA')),parse_float=Decimal)
 
 
 	TwUnspentOutputs.set_dates = fake_set_dates
 	TwUnspentOutputs.set_dates = fake_set_dates

+ 1 - 1
test/test.py

@@ -321,7 +321,7 @@ cfgs = { # addr_idx_lists (except 31,32,33,34) must contain exactly 8 addresses
 	},
 	},
 	'17': {},
 	'17': {},
 	'18': {},
 	'18': {},
-	'19': { 'wpasswd':'abc' }, # B2X
+	'19': { 'wpasswd':'abc' },
 	'20': { 'wpasswd':       'Vsize it',
 	'20': { 'wpasswd':       'Vsize it',
 			'addr_idx_list': '1-8',
 			'addr_idx_list': '1-8',
 			'seed_len':      256,
 			'seed_len':      256,

+ 1 - 1
test/test_py_d/ts_main.py

@@ -380,7 +380,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
 				getrand(32),
 				getrand(32),
 				compressed  = non_mmgen_input_compressed,
 				compressed  = non_mmgen_input_compressed,
 				pubkey_type = 'std' )
 				pubkey_type = 'std' )
-			from mmgen.addr import AddrGenerator,KeyGenerator
+			from mmgen.addr import KeyGenerator,AddrGenerator
 			rand_coinaddr = AddrGenerator(
 			rand_coinaddr = AddrGenerator(
 				self.proto,
 				self.proto,
 				'compressed'
 				'compressed'

+ 3 - 3
test/test_py_d/ts_opts.py

@@ -48,7 +48,7 @@ class TestSuiteOpts(TestSuiteBase):
 	def opt_helpscreen(self):
 	def opt_helpscreen(self):
 		return self.do_run(
 		return self.do_run(
 			['--help'],
 			['--help'],
-			r'OPTS.PY: Opts test.*USAGE:\s+opts.py.*1:python-ecdsa 2:libsecp256k1 \(default: 2\).*'
+			r'OPTS.PY: Opts test.*USAGE:\s+opts.py.*--minconf.*'
 			+ r'NOTES FOR THIS.*a note',
 			+ r'NOTES FOR THIS.*a note',
 			0,
 			0,
 			regex=True )
 			regex=True )
@@ -65,9 +65,9 @@ class TestSuiteOpts(TestSuiteBase):
 					('opt.passwd_file',       'None'),         # infile_opts - check_infile()
 					('opt.passwd_file',       'None'),         # infile_opts - check_infile()
 					('opt.outdir',            'None'),         # check_outdir()
 					('opt.outdir',            'None'),         # check_outdir()
 					('opt.subseeds',          'None'),         # opt_sets_global
 					('opt.subseeds',          'None'),         # opt_sets_global
-					('opt.key_generator',     '2'),            # global_sets_opt
+					('opt.minconf',           '1'),            # global_sets_opt
 					('g.subseeds',            'None'),
 					('g.subseeds',            'None'),
-					('g.key_generator',       '2'),
+					('g.minconf',             '1'),
 				)
 				)
 			)
 			)
 
 

+ 3 - 3
test/test_py_d/ts_regtest.py

@@ -338,10 +338,10 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		if subseed_idx in self.usr_subsids[user]:
 		if subseed_idx in self.usr_subsids[user]:
 			return self.usr_subsids[user][subseed_idx]
 			return self.usr_subsids[user][subseed_idx]
 
 
-		icls = MMGenWallet
-		fn = get_file_with_ext(self._user_dir(user),icls.ext)
+		wcls = MMGenWallet
+		fn = get_file_with_ext(self._user_dir(user),wcls.ext)
 		t = self.spawn('mmgen-tool',['get_subseed',subseed_idx,'wallet='+fn],no_msg=True,no_exec_wrapper=True)
 		t = self.spawn('mmgen-tool',['get_subseed',subseed_idx,'wallet='+fn],no_msg=True,no_exec_wrapper=True)
-		t.passphrase(icls.desc,rt_pw)
+		t.passphrase(wcls.desc,rt_pw)
 		sid = t.read().strip()[:8]
 		sid = t.read().strip()[:8]
 		self.usr_subsids[user][subseed_idx] = sid
 		self.usr_subsids[user][subseed_idx] = sid
 		return sid
 		return sid

+ 0 - 1
test/tooltest2.py

@@ -34,7 +34,6 @@ sys.path.insert(0,overlay_setup(repo_root))
 from mmgen.common import *
 from mmgen.common import *
 from test.include.common import *
 from test.include.common import *
 from mmgen.wallet import is_bip39_mnemonic,is_mmgen_mnemonic
 from mmgen.wallet import is_bip39_mnemonic,is_mmgen_mnemonic
-from mmgen.addr import is_xmrseed
 from mmgen.baseconv import *
 from mmgen.baseconv import *
 
 
 skipped_tests = ['mn2hex_interactive']
 skipped_tests = ['mn2hex_interactive']