Browse Source

minor changes and fixes

MMGen 5 years ago
parent
commit
c82c9c5bd7

+ 4 - 2
mmgen/addr.py

@@ -473,7 +473,8 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 				dmsg('Key {:>03}: {}'.format(pos,e.passwd))
 
 			out.append(e)
-			if g.debug_addrlist: Msg('generate():\n{}'.format(e.pformat()))
+			if g.debug_addrlist:
+				Msg('generate():\n{}'.format(e.ppformat()))
 
 		qmsg('\r{}: {} {}{} generated{}'.format(
 				self.al_id.hl(),t_addrs,self.gen_desc,suf(t_addrs,self.gen_desc_pl),' '*15))
@@ -577,7 +578,8 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 		for n,e in enumerate(d,1):
 			qmsg_r('\rGenerating addresses from keylist: {}/{}'.format(n,len(d)))
 			e.addr = ag.to_addr(kg.to_pubhex(e.sec))
-			if g.debug_addrlist: Msg('generate_addrs_from_keys():\n{}'.format(e.pformat()))
+			if g.debug_addrlist:
+				Msg('generate_addrs_from_keys():\n{}'.format(e.ppformat()))
 		qmsg('\rGenerated addresses from keylist: {}/{} '.format(n,len(d)))
 
 	def format(self,enable_comments=False):

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

@@ -303,7 +303,6 @@ class EthereumTokenTwUnspentOutputs(EthereumTwUnspentOutputs):
 
 	def get_display_precision(self): return 10 # truncate precision for narrow display
 
-	# NB: two wallet instances open simultaneously on the same data:
 	def get_unspent_data(self):
 		super().get_unspent_data()
 		for e in self.unspent:

+ 6 - 2
mmgen/crypto.py

@@ -118,14 +118,18 @@ def scrypt_hash_passphrase(passwd,salt,hash_preset,buflen=32):
 		import scrypt
 		return scrypt.hash(passwd,salt,2**N,r,p,buflen=buflen)
 
-	msg_r('Hashing passphrase...')
+	if int(hash_preset) > 3:
+		msg_r('Hashing passphrase, please wait...')
+
 	# hashlib.scrypt doesn't support N > 14 (hash preset 3)
 	if N > 14 or g.force_standalone_scrypt_module:
 		ret = do_standalone_scrypt()
 	else:
 		try: ret = do_hashlib_scrypt()
 		except: ret = do_standalone_scrypt()
-	msg('done')
+
+	if int(hash_preset) > 3:
+		msg_r('\b'*34 + ' '*34 + '\b'*34)
 
 	return ret
 

+ 5 - 6
mmgen/seed.py

@@ -765,28 +765,27 @@ class Mnemonic (SeedSourceUnenc):
 			while True:
 				r = get_char('\r'+prompt).decode()
 				if r in urange: break
-			msg_r('\r' + ' '*len(prompt) + '\r')
+			msg_r(('\r','\n')[g.test_suite] + ' '*len(prompt) + '\r')
 			return self.mn_lens[int(r)-1]
 
 		while True:
 			mn_len = choose_mn_len()
 			prompt = 'Mnemonic length of {} words chosen. OK?'.format(mn_len)
-			if keypress_confirm(prompt,default_yes=True,no_nl=True): break
-
+			if keypress_confirm(prompt,default_yes=True,no_nl=not g.test_suite):
+				break
 		wl = baseconv.digits[self.wl_id]
 		longest_word = max(len(w) for w in wl)
 		from string import ascii_lowercase
 
-		m  = 'Enter your {ml}-word mnemonic, hitting ENTER or SPACE after each word.\n'
+		m  = 'Enter your {ml}-word seed phrase, hitting ENTER or SPACE after each word.\n'
 		m += "Optionally, you may use pad characters.  Anything you type that's not a\n"
 		m += 'lowercase letter will be treated as a {lq}pad character{rq}, i.e. it will simply\n'
 		m += 'be discarded.  Pad characters may be typed before, after, or in the middle\n'
 		m += "of words.  For each word, once you've typed {lw} characters total (including\n"
-		m += 'pad characters) a pad character will enter the word.'
+		m += 'pad characters) any pad character will enter the word.'
 
 		# pexpect chokes on these utf8 chars under MSYS2
 		lq,rq = (('“','”'),('"','"'))[g.test_suite and g.platform=='win']
-
 		msg(m.format(ml=mn_len,lw=longest_word,lq=lq,rq=rq))
 
 		def get_word():

+ 0 - 6
mmgen/term.py

@@ -58,7 +58,6 @@ def _kb_hold_protect_unix():
 # as well as UTF8 chars (4 bytes max).
 def _get_keypress_unix(prompt='',immed_chars='',prehold_protect=True,num_chars=5):
 	msg_r(prompt)
-	sys.stderr.flush()
 	timeout = float(0.3)
 	fd = sys.stdin.fileno()
 	old = termios.tcgetattr(fd)
@@ -81,7 +80,6 @@ def _get_keypress_unix(prompt='',immed_chars='',prehold_protect=True,num_chars=5
 
 def _get_keypress_unix_raw(prompt='',immed_chars='',prehold_protect=None,num_chars=5):
 	msg_r(prompt)
-	sys.stderr.flush()
 	fd = sys.stdin.fileno()
 	old = termios.tcgetattr(fd)
 	tty.setcbreak(fd)
@@ -91,7 +89,6 @@ def _get_keypress_unix_raw(prompt='',immed_chars='',prehold_protect=None,num_cha
 
 def _get_keypress_unix_stub(prompt='',immed_chars='',prehold_protect=None,num_chars=None):
 	msg_r(prompt)
-	sys.stderr.flush()
 	return sys.stdin.read(1).encode()
 
 #_get_keypress_unix_stub = _get_keypress_unix
@@ -112,7 +109,6 @@ def _kb_hold_protect_mswin():
 def _get_keypress_mswin(prompt='',immed_chars='',prehold_protect=True,num_chars=None):
 
 	msg_r(prompt)
-	sys.stderr.flush()
 	timeout = float(0.5)
 
 	while True:
@@ -135,14 +131,12 @@ def _get_keypress_mswin(prompt='',immed_chars='',prehold_protect=True,num_chars=
 
 def _get_keypress_mswin_raw(prompt='',immed_chars='',prehold_protect=None,num_chars=None):
 	msg_r(prompt)
-	sys.stderr.flush()
 	ch = msvcrt.getch()
 	if ch == b'\x03': raise KeyboardInterrupt
 	return ch
 
 def _get_keypress_mswin_stub(prompt='',immed_chars='',prehold_protect=None,num_chars=None):
 	msg_r(prompt)
-	sys.stderr.flush()
 	return os.read(0,1)
 
 def _get_terminal_size_linux():

+ 14 - 10
mmgen/util.py

@@ -31,11 +31,13 @@ if g.platform == 'win':
 	def msg_r(s):
 		try:
 			g.stderr.write(s)
+			g.stderr.flush()
 		except:
 			os.write(2,s.encode())
 	def Msg_r(s):
 		try:
 			g.stdout.write(s)
+			g.stdout.flush()
 		except:
 			os.write(1,s.encode())
 	def msg(s): msg_r(s + '\n')
@@ -300,16 +302,16 @@ class baseconv(object):
 
 	@classmethod
 	def b58encode(cls,s,pad=None):
-		pad = cls.get_pad(s,pad,'b58encode',cls.b58pad_lens,(bytes,))
+		pad = cls._get_pad(s,pad,'b58encode',cls.b58pad_lens,(bytes,))
 		return cls.fromhex(s.hex(),'b58',pad=pad,tostr=True)
 
 	@classmethod
 	def b58decode(cls,s,pad=None):
-		pad = cls.get_pad(s,pad,'b58decode',cls.b58pad_lens_rev,(bytes,str))
+		pad = cls._get_pad(s,pad,'b58decode',cls.b58pad_lens_rev,(bytes,str))
 		return bytes.fromhex(cls.tohex(s,'b58',pad=pad*2 if pad else None))
 
 	@staticmethod
-	def get_pad(s,pad,op_desc,pad_map,ok_types):
+	def _get_pad(s,pad,op_desc,pad_map,ok_types):
 		if not isinstance(s,ok_types):
 			m = "{}() input must be one of {}, not '{}'"
 			raise ValueError(m.format(op_desc,repr([t.__name__ for t in ok_types]),type(s).__name__))
@@ -329,21 +331,21 @@ class baseconv(object):
 
 	@classmethod
 	def check_wordlists(cls):
-		for k,v in list(cls.wl_chksums.items()): assert cls.get_wordlist_chksum(k) == v
+		for k,v in list(cls.wl_chksums.items()):
+			res = cls.get_wordlist_chksum(k)
+			assert res == v,'{}: checksum mismatch for {} (should be {})'.format(res,k,v)
 
 	@classmethod
 	def check_wordlist(cls,wl_id):
 
-		wl = baseconv.digits[wl_id]
-		Msg('Wordlist: {}\nLength: {} words'.format(capfirst(wl_id),len(wl)))
+		wl = cls.digits[wl_id]
+		qmsg('Wordlist: {}\nLength: {} words'.format(wl_id,len(wl)))
 		new_chksum = cls.get_wordlist_chksum(wl_id)
 
-		a,b = 'generated checksum','saved checksum'
+		a,b = 'generated','saved'
 		compare_chksums(new_chksum,a,cls.wl_chksums[wl_id],b,die_on_fail=True)
 
-		Msg('Checksum {} matches'.format(new_chksum))
-		Msg('List is sorted') if tuple(sorted(wl)) == wl else die(3,'ERROR: List is not sorted!')
-
+		qmsg('List is sorted') if tuple(sorted(wl)) == wl else die(3,'ERROR: List is not sorted!')
 
 	@classmethod
 	def tohex(cls,words_arg,wl_id,pad=None):
@@ -362,6 +364,8 @@ class baseconv(object):
 
 	@classmethod
 	def fromhex(cls,hexnum,wl_id,pad=None,tostr=False):
+		if wl_id in ('electrum','tirosh'):
+			assert tostr == False,"'tostr' must be False for '{}'".format(wl_id)
 
 		if not is_hex_str(hexnum):
 			die(2,"{!r}: not a hexadecimal number".format(hexnum))

+ 6 - 2
test/scrambletest.py

@@ -94,7 +94,11 @@ def run_tests():
 		msg_r('Testing: --coin {:4} {:22}'.format(coin.upper(),type_arg))
 		p = subprocess.Popen(cmd.split(),stdout=subprocess.PIPE,stderr=subprocess.PIPE)
 		o = p.stdout.read().decode()
-		vmsg(o)
+		err = p.stderr.read().decode()
+		exit_val = p.wait()
+		if exit_val != 0:
+			ydie(2,'\nSpawned program exited with error code {}:\n{}'.format(exit_val,err))
+		vmsg('\nCOMMAND OUTPUT:\n[{}]'.format(o))
 		o = o.splitlines()
 		d = [e for e in o if len(e) > 4 and e[:9] == 'sc_debug_']
 		d.append('sc_debug_addr: ' + o[-2].split()[-1])
@@ -103,7 +107,7 @@ def run_tests():
 			a = test_data[test][n]
 			b = [e for e in d if e[:len(kk)] == kk][0][len(kk)+2:]
 			if b == a:
-				vmsg('sc_{}: {}'.format(k,a))
+				vmsg('sc_debug_{}: {}'.format(k,a))
 			else:
 				rdie(1,'\nError: sc_{} value {} does not match reference value {}'.format(k,b,a))
 		msg('OK')

+ 9 - 5
test/test_py_d/common.py

@@ -46,6 +46,7 @@ non_mmgen_fn = 'coinkey'
 
 ref_dir = os.path.join('test','ref')
 dfl_words_file = os.path.join(ref_dir,'98831F3A.mmwords')
+mn_words_mmgen = os.path.join(ref_dir,'FE3C6545.mmwords')
 
 from mmgen.obj import MMGenTXLabel,TwComment
 
@@ -146,23 +147,26 @@ def get_label(do_shuffle=False):
 		label_iter = iter(labels)
 		return next(label_iter)
 
-def stealth_mnemonic_entry(t,mn):
+def stealth_mnemonic_entry(t,mn,fmt):
 	wnum = 1
-	max_wordlen = 12
+	max_wordlen = { 'words': 12 }[fmt]
 
 	def get_pad_chars(n):
 		ret = ''
 		for i in range(n):
-			m = int(os.urandom(1).hex(),16) % 32
+			m = int.from_bytes(os.urandom(1),'big') % 32
 			ret += r'123579!@#$%^&*()_+-=[]{}"?/,.<>|'[m]
 		return ret
 
 	for i in range(len(mn)):
 		w = mn[i]
-		if len(w) > 5:
+		if len(w) > (3,5)[max_wordlen==12]:
 			w = w + '\n'
 		else:
-			w = get_pad_chars(3 if randbool() else 0) + w[0] + get_pad_chars(3) + w[1:] + get_pad_chars(7)
+			w = (
+				get_pad_chars(2 if randbool() else 0)
+				+ w[0] + get_pad_chars(2) + w[1:]
+				+ get_pad_chars(9) )
 			w = w[:max_wordlen+1]
 		em,rm = 'Enter word #{}: ','Repeat word #{}: '
 		ret = t.expect((em.format(wnum),rm.format(wnum-1)))

+ 1 - 1
test/test_py_d/ts_autosign.py

@@ -67,7 +67,7 @@ class TestSuiteAutosign(TestSuiteBase):
 			mn_file = dfl_words_file
 			mn = read_from_file(mn_file).strip().split()
 			mn = ['foo'] + mn[:5] + ['realiz','realized'] + mn[5:]
-			stealth_mnemonic_entry(t,mn)
+			stealth_mnemonic_entry(t,mn,fmt='words')
 			wf = t.written_to_file('Autosign wallet')
 			t.ok()
 

+ 8 - 6
test/test_py_d/ts_misc.py

@@ -141,20 +141,22 @@ class TestSuiteInput(TestSuiteBase):
 			return 'skip' # pexpect double-escapes utf8, so skip
 		return self.password_entry('Enter passphrase (echoed): ',['--echo-passphrase'])
 
-	def mnemonic_entry(self):
-		mn = read_from_file(dfl_words_file).strip().split()[:12]
-		mn = ['foo'] + mn[:5] + ['realiz','realized'] + mn[5:]
-		t = self.spawn('mmgen-walletconv',['-S','-i','words','-o','words'])
+	def _mnemonic_entry(self,fmt,wf):
+		mn = read_from_file(wf).strip().split()
+		mn = ['foo'] + mn[:5] + ['grac','graceful'] + mn[5:]
+		t = self.spawn('mmgen-walletconv',['-S','-i',fmt,'-o',fmt])
 		t.expect('words: ','1')
 		t.expect('(Y/n): ','y')
-		stealth_mnemonic_entry(t,mn)
-		sid_chk = '5F9BC42F'
+		stealth_mnemonic_entry(t,mn,fmt=fmt)
+		sid_chk = 'FE3C6545'
 		sid = t.expect_getend('Valid mnemonic data for Seed ID ')[:8]
 		assert sid == sid_chk,'Seed ID mismatch! {} != {}'.format(sid,sid_chk)
 		t.expect('to confirm: ','YES\n')
 		t.read()
 		return t
 
+	def mnemonic_entry(self): return self._mnemonic_entry('words',mn_words_mmgen)
+
 class TestSuiteTool(TestSuiteMain,TestSuiteBase):
 	"tests for interactive 'mmgen-tool' commands"
 	networks = ('btc',)

+ 1 - 1
test/unit_tests_d/ut_subseed.py

@@ -53,7 +53,7 @@ class unit_test(object):
 				seed2.subseeds._generate(10)
 				assert len(ss2_list) == 10, len(ss2_list)
 
-				assert seed.pformat() == seed2.pformat()
+				assert seed.ppformat() == seed2.ppformat()
 
 				s = seed.subseeds.format(1,g.subseeds)
 				s_lines = s.strip().split('\n')