Browse Source

various minor fixes and cleanups

MMGen 5 years ago
parent
commit
3a09017804
16 changed files with 67 additions and 28 deletions
  1. 4 0
      MANIFEST.in
  2. 2 3
      mmgen/addr.py
  3. 2 0
      mmgen/common.py
  4. 3 2
      mmgen/crypto.py
  5. 1 0
      mmgen/globalvars.py
  6. 5 5
      mmgen/main.py
  7. 11 6
      mmgen/main_wallet.py
  8. 2 1
      mmgen/obj.py
  9. 1 0
      mmgen/opts.py
  10. 6 3
      mmgen/tool.py
  11. 6 2
      mmgen/util.py
  12. 0 2
      setup.py
  13. 2 0
      test/objtest.py
  14. 0 1
      test/test_py_d/ts_main.py
  15. 20 2
      test/tooltest2.py
  16. 2 1
      test/unit_tests.py

+ 4 - 0
MANIFEST.in

@@ -1,5 +1,6 @@
 include README.md SIGNING_KEYS.pub LICENSE INSTALL
 include doc/wiki/using-mmgen/*
+
 include test/*.py
 include test/test_py_d/*.py
 include test/ref/*
@@ -10,6 +11,9 @@ include test/ref/dash/*
 include test/ref/zcash/*
 include test/ref/monero/*
 
+include mmgen/altcoins/eth/rlp/LICENSE
+include mmgen/altcoins/eth/pyethereum/LICENSE
+
 include scripts/compute-file-chksum.py
 include scripts/create-token.py
 include scripts/test-release.sh

+ 2 - 3
mmgen/addr.py

@@ -375,7 +375,6 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 	gen_keys = False
 	has_keys = False
 	ext      = 'addrs'
-	scramble_hash_rounds = 10  # not too many rounds, so hand decoding can still be feasible
 	chksum_rec_f = lambda foo,e: (str(e.idx), e.addr)
 
 	def __init__(self,addrfile='',al_id='',adata=[],seed='',addr_idxs='',src='',
@@ -497,7 +496,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 		if g.proto.is_testnet():
 			scramble_key += ':testnet'
 		dmsg_sc('str',scramble_key)
-		return scramble_seed(seed,scramble_key.encode(),self.scramble_hash_rounds)
+		return scramble_seed(seed,scramble_key.encode(),g.scramble_hash_rounds)
 
 	def encrypt(self,desc='new key list'):
 		from mmgen.crypto import mmgen_encrypt
@@ -886,7 +885,7 @@ Record this checksum: it will be used to verify the password file in the future
 		# NB: In original implementation, pw_id_str was 'baseN', not 'bN'
 		scramble_key = '{}:{}:{}'.format(self.pw_fmt,self.pw_len,self.pw_id_str)
 		from mmgen.crypto import scramble_seed
-		return scramble_seed(seed,scramble_key.encode(),self.scramble_hash_rounds)
+		return scramble_seed(seed,scramble_key.encode(),g.scramble_hash_rounds)
 
 class AddrData(MMGenObject):
 	msgs = {

+ 2 - 0
mmgen/common.py

@@ -41,6 +41,8 @@ def help_notes(k):
 		'rel_fee_desc': MMGenTX().rel_fee_desc,
 		'fee_spec_letters': fee_spec_letters(),
 		'passwd': """
+PASSPHRASE NOTE:
+
 For passphrases all combinations of whitespace are equal, and leading and
 trailing space are ignored.  This permits reading passphrase or brainwallet
 data from a multi-line file with free spacing and indentation.

+ 3 - 2
mmgen/crypto.py

@@ -45,8 +45,9 @@ def sha256_rounds(s,n):
 def scramble_seed(seed,scramble_key,hash_rounds):
 	import hmac
 	scr_seed = hmac.new(seed,scramble_key,sha256).digest()
-	fs = 'Seed:  {}\nScramble key: {}\nScrambled seed: {}'
-	dmsg(fs.format(seed.hex(),scramble_key.decode(),scr_seed.hex()))
+	if g.debug:
+		fs = 'Seed:  {!r}\nScramble key: {}\nScrambled seed: {}\n'
+		msg(fs.format(seed.hex(),scramble_key,scr_seed.hex()))
 	return sha256_rounds(scr_seed,hash_rounds)
 
 def encrypt_seed(seed,key):

+ 1 - 0
mmgen/globalvars.py

@@ -200,6 +200,7 @@ class g(object):
 	min_urandchars = 10
 
 	seed_lens = 128,192,256
+	scramble_hash_rounds = 10
 
 	mmenc_ext      = 'mmenc'
 	salt_len       = 16

+ 5 - 5
mmgen/main.py

@@ -20,11 +20,11 @@
 main.py - Script launcher for the MMGen suite
 """
 
-def launch(what):
+def launch(mod):
 
-	if what in ('walletgen','walletchk','walletconv','passchg'):
-		what = 'wallet'
-	if what == 'keygen': what = 'addrgen'
+	if mod in ('walletgen','walletchk','walletconv','passchg'):
+		mod = 'wallet'
+	if mod == 'keygen': mod = 'addrgen'
 
 	import sys,os
 	from mmgen.globalvars import g
@@ -36,7 +36,7 @@ def launch(what):
 		atexit.register(lambda: termios.tcsetattr(fd,termios.TCSADRAIN,old))
 
 	try:
-		__import__('mmgen.main_' + what)
+		__import__('mmgen.main_' + mod)
 	except KeyboardInterrupt:
 		sys.stderr.write('\nUser interrupt\n')
 	except EOFError:

+ 11 - 6
mmgen/main_wallet.py

@@ -30,8 +30,14 @@ usage = '[opts] [infile]'
 nargs = 1
 iaction = 'convert'
 oaction = 'convert'
-invoked_as = 'passchg' if g.prog_name == 'mmgen-passchg' else g.prog_name.partition('-wallet')[2]
-bw_note = True
+do_bw_note = True
+
+invoked_as = {
+	'mmgen-walletgen':    'gen',
+	'mmgen-walletconv':   'conv',
+	'mmgen-walletchk':    'chk',
+	'mmgen-passchg':      'passchg',
+}[g.prog_name]
 
 # full: defhHiJkKlLmoOpPqrSvz-
 if invoked_as == 'gen':
@@ -51,9 +57,7 @@ elif invoked_as == 'passchg':
 	desc = 'Change the passphrase, hash preset or label of an {pnm} wallet'
 	opt_filter = 'efhdiHkKOlLmpPqrSvz-'
 	iaction = 'input'
-	bw_note = False
-else:
-	die(1,"'{}': unrecognized invocation".format(g.prog_name))
+	do_bw_note = False
 
 opts_data = {
 	'text': {
@@ -108,7 +112,7 @@ FMT CODES:
 		'notes': lambda s: s.format(
 			f='\n  '.join(SeedSource.format_fmt_codes().splitlines()),
 			n_pw=help_notes('passwd'),
-			n_bw=('','\n\n' + help_notes('brainwallet'))[bw_note]
+			n_bw=('','\n\n'+help_notes('brainwallet'))[do_bw_note]
 		)
 	}
 }
@@ -128,6 +132,7 @@ if invoked_as in ('conv','passchg'):
 	msg(m1+m2)
 
 ss_in = None if invoked_as == 'gen' else SeedSource(sf,passchg=(invoked_as=='passchg'))
+
 if invoked_as == 'chk':
 	lbl = ss_in.ssdata.label.hl() if hasattr(ss_in.ssdata,'label') else 'NONE'
 	vmsg('Wallet label: {}'.format(lbl))

+ 2 - 1
mmgen/obj.py

@@ -118,7 +118,8 @@ class InitErrors(object):
 
 	@staticmethod
 	def arg_chk(cls,on_fail):
-		assert on_fail in ('die','return','silent','raise'),'arg_chk in class {}'.format(cls.__name__)
+		assert on_fail in ('die','return','silent','raise'),(
+			"'{}': invalid value for 'on_fail' in class {}".format(on_fail,cls.__name__) )
 
 	@staticmethod
 	def init_fail(m,on_fail):

+ 1 - 0
mmgen/opts.py

@@ -331,6 +331,7 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
 
 	if hasattr(g,'cfg_options_changed'):
 		ymsg("Warning: config file options have changed! See '{}' for details".format(g.cfg_file+'.sample'))
+		from mmgen.util import my_raw_input
 		my_raw_input('Hit ENTER to continue: ')
 
 	if g.debug and g.prog_name != 'test.py':

+ 6 - 3
mmgen/tool.py

@@ -94,6 +94,8 @@ def _usage(cmd=None,exit_val=1):
 			Msg('')
 		Msg(m2)
 	elif cmd in MMGenToolCmd._user_commands():
+		docstr = getattr(MMGenToolCmd,cmd).__doc__.strip()
+		msg('{}\n'.format(capfirst(docstr)))
 		msg('USAGE: {} {} {}'.format(g.prog_name,cmd,_create_call_sig(cmd)))
 	else:
 		die(1,"'{}': no such tool command".format(cmd))
@@ -678,8 +680,8 @@ class MMGenToolCmdWallet(MMGenToolCmdBase):
 	def gen_addr(self,mmgen_addr:str,wallet='',target='addr'):
 		"generate a single MMGen address from default or specified wallet"
 		addr = MMGenID(mmgen_addr)
-		sf = get_seed_file([wallet] if wallet else [],1)
 		opt.quiet = True
+		sf = get_seed_file([wallet] if wallet else [],1)
 		from mmgen.seed import SeedSource
 		ss = SeedSource(sf)
 		if ss.seed.sid != addr.sid:
@@ -885,8 +887,9 @@ class MMGenToolCmdMonero(MMGenToolCmdBase):
 			while True:
 				ret = p.expect([r' / .*',r'\[wallet.*:.*'])
 				if ret == 0: # TODO: coverage
-					height = p.after
-					msg_r('\r  Block {}{}'.format(p.before.split()[-1],height))
+					cur_block = p.before.decode().split()[-1]
+					height = p.after.decode()
+					msg_r('\r  Block {}{}'.format(cur_block,height))
 				elif ret == 1:
 					if height:
 						height = height.split()[-1]

+ 6 - 2
mmgen/util.py

@@ -41,8 +41,12 @@ if g.platform == 'win':
 	def msg(s): msg_r(s + '\n')
 	def Msg(s): Msg_r(s + '\n')
 else:
-	def msg_r(s): g.stderr.write(s)
-	def Msg_r(s): g.stdout.write(s)
+	def msg_r(s):
+		g.stderr.write(s)
+		g.stderr.flush()
+	def Msg_r(s):
+		g.stdout.write(s)
+		g.stdout.flush()
 	def msg(s):   g.stderr.write(s + '\n')
 	def Msg(s):   g.stdout.write(s + '\n')
 

+ 0 - 2
setup.py

@@ -117,12 +117,10 @@ setup(
 			'mmgen.altcoins.eth.tx',
 			'mmgen.altcoins.eth.tw',
 
-			'mmgen/altcoins/eth/pyethereum/LICENSE',
 			'mmgen.altcoins.eth.pyethereum.__init__',
 			'mmgen.altcoins.eth.pyethereum.transactions',
 			'mmgen.altcoins.eth.pyethereum.utils',
 
-			'mmgen/altcoins/eth/rlp/LICENSE',
 			'mmgen/altcoins/eth/rlp/__init__',
 			'mmgen/altcoins/eth/rlp/atomic',
 			'mmgen/altcoins/eth/rlp/codec',

+ 2 - 0
test/objtest.py

@@ -67,6 +67,8 @@ def run_test(test,arg,input_data):
 			del arg['ret']
 			del arg_copy['ret']
 		kwargs.update(arg)
+	elif type(arg) == tuple:
+		args = arg
 	else:
 		args = [arg]
 	try:

+ 0 - 1
test/test_py_d/ts_main.py

@@ -199,7 +199,6 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
 			t.expect('move it to the data directory? (Y/n): ','y')
 			self.have_dfl_wallet = True
 		t.written_to_file('MMGen wallet')
-		t.req_exit_val = 0
 		return t
 
 	def passchg(self,wf,pf,label_action='cmdline'):

+ 20 - 2
test/tooltest2.py

@@ -40,6 +40,15 @@ from mmgen.seed import is_mnemonic
 
 def is_str(s): return type(s) == str
 
+def md5_hash(s):
+	from hashlib import md5
+	return md5(s.encode()).hexdigest()
+
+def md5_hash_strip(s):
+	import re
+	s = re.sub('\x1b\[[;0-9]+?m','',s) # strip ANSI color sequences
+	return md5_hash(s.strip())
+
 opts_data = {
 	'text': {
 		'desc': "Simple test suite for the 'mmgen-tool' utility",
@@ -592,7 +601,12 @@ def run_test(gid,cmd_name):
 		cmd_err = p.stderr.read()
 		if cmd_err: vmsg(cmd_err.strip().decode())
 		if p.wait() != 0:
-			die(1,'Spawned program exited with error')
+			import re
+			m = re.match(b"tool command returned '(None|False)'\n",cmd_err)
+			if m:
+				return { b'None': None, b'False': False }[m.group(1)]
+			else:
+				ydie(1,'Spawned program exited with error: {}'.format(cmd_err))
 
 		return cmd_out
 
@@ -655,7 +669,11 @@ def run_test(gid,cmd_name):
 			elif out is not None:
 				assert cmd_out == out,"Output ({!r}) doesn't match expected output ({!r})".format(cmd_out,out)
 
-		if type(out) in (list,tuple):
+		if type(out) == tuple and type(out[0]).__name__ == 'function':
+			func_out = out[0](cmd_out)
+			assert func_out == out[1],(
+				"{}({}) == {} failed!\nOutput: {}".format(out[0].__name__,cmd_out,out[1],func_out))
+		elif type(out) in (list,tuple):
 			for co,o in zip(cmd_out.split('\n') if opt.fork else cmd_out,out):
 				check_output(co,o)
 		else:

+ 2 - 1
test/unit_tests.py

@@ -117,7 +117,8 @@ class UnitTests(object):
 					extra_desc,
 					'' if opt.quiet else '\n'))
 			else:
-				Msg('Testing transactions from {!r}'.format(fn))
+				Msg_r('Testing transactions from {!r}'.format(fn))
+				if not opt.quiet: Msg('')
 
 		def test_core_vectors():
 			self._get_core_repo_root()