Browse Source

various fixes and cleanups throughout

The MMGen Project 5 years ago
parent
commit
70675956b8

+ 16 - 12
data_files/mmgen.cfg

@@ -52,15 +52,6 @@
 # Set the maximum transaction fee for BTC:
 # btc_max_tx_fee 0.003
 
-# Set the maximum transaction fee for BCH:
-# bch_max_tx_fee 0.1
-
-# Set the maximum transaction fee for LTC:
-# ltc_max_tx_fee 0.3
-
-# Set the maximum transaction fee for ETH:
-# eth_max_tx_fee 0.005
-
 # Set the transaction fee adjustment factor. Auto-calculated fees are
 # multiplied by this value:
 # tx_fee_adj 1.0
@@ -71,15 +62,28 @@
 # Set the maximum input size - applies both to files and standard input:
 # max_input_size 1048576
 
+# Uncomment to suppress non-ASCII character password warning for MSWin / MSYS2
+# mswin_pw_warning false
+
+###################
+# Altcoin options #
+###################
+
+# Set the maximum transaction fee for BCH:
+# bch_max_tx_fee 0.1
+
+# Set the maximum transaction fee for LTC:
+# ltc_max_tx_fee 0.3
+
+# Set the maximum transaction fee for ETH:
+# eth_max_tx_fee 0.005
+
 # Set the Ethereum mainnet name
 # eth_mainnet_chain_name foundation
 
 # Set the Ethereum testnet name
 # eth_testnet_chain_name kovan
 
-# Uncomment to suppress non-ASCII character password warning for MSWin / MSYS2
-# mswin_pw_warning false
-
 #####################################################################
 # The following options are probably of interest only to developers #
 #####################################################################

+ 3 - 3
mmgen/addr.py

@@ -795,8 +795,8 @@ class PasswordList(AddrList):
 # password.  The label may contain any printable ASCII symbol.
 #
 """.strip().format(n=TwComment.max_screen_width,pnm=pnm),
-	'file_header_bip39': """
-# {pnm} BIP39 password file
+	'file_header_mn': """
+# {pnm} {{}} password file
 #
 # This file is editable.
 # Everything following a hash symbol '#' is a comment and ignored by {pnm}.
@@ -856,7 +856,7 @@ Record this checksum: it will be used to verify the password file in the future
 			self.data = self.generate(seed,pw_idxs)
 
 		if self.pw_fmt == 'bip39':
-			self.msgs['file_header'] = self.msgs['file_header_bip39']
+			self.msgs['file_header'] = self.msgs['file_header_mn'].format(self.pw_fmt.upper())
 
 		self.num_addrs = len(self.data)
 		self.fmt_data = ''

+ 1 - 1
mmgen/baseconv.py

@@ -37,7 +37,7 @@ class baseconv(object):
 		'b6d':   ('base6d (die roll)', 'base6 data using the digits from one to six'),
 		'tirosh':('Tirosh mnemonic',   'base1626 mnemonic using truncated Tirosh wordlist'), # not used by wallet
 		'mmgen': ('MMGen native mnemonic',
-		'MMGen native mnemonic seed phrase data created using old Electrum wordlist and simple base conversion'),
+		'MMGen native mnemonic seed phrase created using old Electrum wordlist and simple base conversion'),
 	}
 	# https://en.wikipedia.org/wiki/Base32#RFC_4648_Base32_alphabet
 	# https://tools.ietf.org/html/rfc4648

+ 6 - 6
mmgen/daemon.py

@@ -32,7 +32,7 @@ class Daemon(MMGenObject):
 	debug = False
 	wait = True
 	use_pidfile = True
-	conf_file = None
+	cfg_file = None
 
 	def subclass_init(self): pass
 
@@ -97,8 +97,8 @@ class Daemon(MMGenObject):
 				msg(m.format(self.net_desc,self.desc,self.pid))
 		else:
 			os.makedirs(self.datadir,exist_ok=True)
-			if self.conf_file:
-				open('{}/{}'.format(self.datadir,self.conf_file),'w').write(self.cfg_file_hdr)
+			if self.cfg_file:
+				open('{}/{}'.format(self.datadir,self.cfg_file),'w').write(self.cfg_file_hdr)
 			if self.use_pidfile and os.path.exists(self.pidfile):
 				# Parity just overwrites the data in an existing pidfile, leading to
 				# interesting consequences.
@@ -125,7 +125,7 @@ class Daemon(MMGenObject):
 				return True
 			time.sleep(0.2)
 		else:
-			die(2,'Daemon wait timeout for {} {} exceeded'.format(self.coin,self.network))
+			die(2,'Daemon wait timeout for {} {} exceeded'.format(self.daemon_id.upper(),self.network))
 
 	@property
 	def is_ready(self):
@@ -361,11 +361,11 @@ class EthereumDaemon(CoinDaemon):
 
 	@property
 	def stop_cmd(self):
-		return ['kill','-Wf',self.pid] if g.platform == 'win' else ['kill',self.pid]
+		return ['kill','-Wf',self.pid] if self.platform == 'win' else ['kill',self.pid]
 
 	@property
 	def pid(self): # TODO: distinguish between ETH and ETC
-		if g.platform == 'win':
+		if self.platform == 'win':
 			cp = self.run_cmd(['ps','-Wl'],silent=True,check=False)
 			for line in cp.stdout.decode().splitlines():
 				if 'parity.exe' in line:

+ 1 - 1
mmgen/main_autosign.py

@@ -357,7 +357,7 @@ def setup():
 	opt.quiet = True
 	opt.in_fmt = 'words'
 	ss_in = SeedSource()
-	opt.out_fmt = 'mmdat'
+	opt.out_fmt = 'wallet'
 	opt.usr_randchars = 0
 	opt.hash_preset = '1'
 	opt.set_by_user = ['hash_preset']

+ 6 - 1
mmgen/mn_electrum.py

@@ -15,12 +15,17 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
 # ------------------------------------------------------------------------------
+
 # MMGen note: this is a sorted version of the wordlist.
-# The original can be found at:
+# The unsorted original can be found at:
 #    https://github.com/spesmilo/electrum/blob/1.9.5/lib/mnemonic.py
 # Electrum - lightweight Bitcoin client. Copyright (C) 2011 thomasv@gitorious
 
+# Also available at:
+#    https://github.com/monero-project/monero/blob/master/src/mnemonics/english_old.h
+
 words = tuple("""
 able
 about

+ 3 - 1
mmgen/obj.py

@@ -489,7 +489,9 @@ class BTCAmt(Decimal,Hilite,InitErrors):
 class BCHAmt(BTCAmt): pass
 class B2XAmt(BTCAmt): pass
 class LTCAmt(BTCAmt): max_amt = 84000000
-class XMRAmt(BTCAmt): min_coin_unit = Decimal('0.000000000001')
+class XMRAmt(BTCAmt):
+	min_coin_unit = Decimal('0.000000000001')
+	units = ('min_coin_unit',)
 
 from mmgen.altcoins.eth.obj import ETHAmt,ETHNonce
 

+ 3 - 3
mmgen/rpc.py

@@ -29,7 +29,7 @@ def dmsg_rpc(fs,data=None,is_json=False):
 	if g.debug_rpc:
 		msg(fs if data == None else fs.format(pp_fmt(json.loads(data) if is_json else data)))
 
-class CoinDaemonRPCConnection(MMGenObject):
+class RPCConnection(MMGenObject):
 
 	auth = True
 	db_fs = '    host [{h}] port [{p}] user [{u}] passwd [{pw}] auth_cookie [{c}]\n'
@@ -217,7 +217,7 @@ class CoinDaemonRPCConnection(MMGenObject):
 		'walletpassphrase',
 	)
 
-class EthereumRPCConnection(CoinDaemonRPCConnection):
+class EthereumRPCConnection(RPCConnection):
 
 	auth = False
 	db_fs = '    host [{h}] port [{p}]\n'
@@ -335,7 +335,7 @@ def init_daemon_bitcoind():
 
 	cfg = get_daemon_cfg_options(('rpcuser','rpcpassword'))
 
-	conn = CoinDaemonRPCConnection(
+	conn = RPCConnection(
 				g.rpc_host or 'localhost',
 				g.rpc_port or g.proto.rpc_port,
 				g.rpc_user or cfg['rpcuser'], # MMGen's rpcuser,rpcpassword override coin daemon's

+ 17 - 12
mmgen/tool.py

@@ -241,7 +241,7 @@ class MMGenToolCmdBase(object):
 
 	@classmethod
 	def _user_commands(cls):
-		return [e for e in dir(cls) if e[0] != '_' and getattr(cls,e).__doc__]
+		return [e for e in dir(cls) if e[0] != '_' and getattr(cls,e).__doc__ and callable(getattr(cls,e))]
 
 
 class MMGenToolCmdMisc(MMGenToolCmdBase):
@@ -393,7 +393,7 @@ class MMGenToolCmdCoin(MMGenToolCmdBase):
 	def hex2wif(self,privhex:'sstr'):
 		"convert a private key from hex to WIF format"
 		init_generators('at')
-		return g.proto.hex2wif(privhex,pubkey_type=at.pubkey_type,compressed=at.compressed)
+		return PrivKey(bytes.fromhex(privhex),pubkey_type=at.pubkey_type,compressed=at.compressed).wif
 
 	def wif2addr(self,wifkey:'sstr'):
 		"generate a coin address from a key in WIF format"
@@ -487,9 +487,10 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase):
 	"""
 	def _do_random_mn(self,nbytes:int,fmt:str):
 		assert nbytes in (16,24,32), 'nbytes must be 16, 24 or 32'
-		hexrand = get_random(nbytes).hex()
-		Vmsg('Seed: {}'.format(hexrand))
-		return self.hex2mn(hexrand,fmt=fmt)
+		randbytes = get_random(nbytes)
+		if opt.verbose:
+			msg('Seed: {}'.format(randbytes.hex()))
+		return self.hex2mn(randbytes.hex(),fmt=fmt)
 
 	def mn_rand128(self, fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"generate random 128-bit mnemonic seed phrase"
@@ -512,17 +513,21 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase):
 	def hex2mn( self, hexstr:'sstr', fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"convert a 16, 24 or 32-byte hexadecimal number to a mnemonic seed phrase"
 		opt.out_fmt = self._get_mnemonic_fmt(fmt)
-		from mmgen.seed import SeedSource
-		s = SeedSource(seed_bin=bytes.fromhex(hexstr))
-		s._format()
-		return ' '.join(s.ssdata.mnemonic)
+		if fmt == 'bip39':
+			from mmgen.bip39 import bip39
+			return ' '.join(bip39.fromhex(hexstr,fmt))
+		else:
+			bytestr = bytes.fromhex(hexstr)
+			return baseconv.frombytes(bytestr,fmt,'seed',tostr=True)
 
 	def mn2hex( self, seed_mnemonic:'sstr', fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"convert a 12, 18 or 24-word mnemonic seed phrase to a hexadecimal number"
 		in_fmt = self._get_mnemonic_fmt(fmt)
-		opt.quiet = True
-		from mmgen.seed import SeedSource
-		return SeedSource(in_data=seed_mnemonic,in_fmt=in_fmt).seed.hexdata
+		if fmt == 'bip39':
+			from mmgen.bip39 import bip39
+			return bip39.tohex(seed_mnemonic.split(),fmt)
+		else:
+			return baseconv.tohex(seed_mnemonic.split(),fmt,'seed')
 
 	def mn_stats(self, fmt:mn_opts_disp = dfl_mnemonic_fmt ):
 		"show stats for mnemonic wordlist"

+ 4 - 3
test/scrambletest.py

@@ -42,7 +42,7 @@ opts_data = {
 -v, --verbose       Produce more verbose output
 """,
 	'notes': """
-
+Valid commands: 'coin','pw'
 If no command is given, the whole suite of tests is run.
 """
 	}
@@ -141,8 +141,9 @@ def do_passwd_tests():
 
 start_time = int(time.time())
 
-do_coin_tests()
-do_passwd_tests()
+cmds = cmd_args or ('coin','pw')
+for cmd in cmds:
+	{'coin': do_coin_tests, 'pw': do_passwd_tests }[cmd]()
 
 t = int(time.time()) - start_time
 m = 'All requested tests finished OK, elapsed time: {:02}:{:02}'

+ 2 - 0
test/test.py

@@ -526,6 +526,8 @@ class CmdGroupMgr(object):
 			if is3seed:
 				for n,(i,j) in enumerate(zip(cls.tmpdir_nums,(128,192,256))):
 					k = '{}_{}'.format(a,n+1)
+					if hasattr(cls,'skip_cmds') and k in cls.skip_cmds:
+						continue
 					sdeps = get_shared_deps(k,i)
 					if type(b) == str:
 						cdata.append( (k, (i,'{} ({}-bit)'.format(b,j),[[[]+sdeps,i]])) )

+ 6 - 6
test/test_py_d/ts_ref_3seed.py

@@ -381,12 +381,12 @@ class TestSuiteRef3Addr(TestSuiteRef3Seed):
 		ea = ['--accept-defaults']
 		return self.pwgen('passhex','фубар@crypto.org','hex','h',ea,stdout=True)
 
-	def bip39pwgen(self,req_pw_len,pwfmt='bip39',stdout=False):
+	def mn_pwgen(self,req_pw_len,pwfmt,ftype='passbip39',stdout=False):
 		pwlen = min(req_pw_len,{'1':12,'2':18,'3':24}[self.test_name[-1]])
 		ea = ['--accept-defaults']
-		return self.pwgen('passbip39','фубар@crypto.org',pwfmt,pwlen,ea,stdout=stdout)
+		return self.pwgen(ftype,'фубар@crypto.org',pwfmt,pwlen,ea,stdout=stdout)
 
-	def ref_bip39_12_passwdgen(self):     return self.bip39pwgen(12,stdout=True)
-	def ref_bip39_18_passwdgen(self):     return self.bip39pwgen(18,stdout=True)
-	def ref_bip39_24_passwdgen(self):     return self.bip39pwgen(24)
-	def ref_hex2bip39_24_passwdgen(self): return self.bip39pwgen(24,'hex2bip39')
+	def ref_bip39_12_passwdgen(self):     return self.mn_pwgen(12,'bip39',stdout=True)
+	def ref_bip39_18_passwdgen(self):     return self.mn_pwgen(18,'bip39',stdout=True)
+	def ref_bip39_24_passwdgen(self):     return self.mn_pwgen(24,'bip39')
+	def ref_hex2bip39_24_passwdgen(self): return self.mn_pwgen(24,'hex2bip39')

+ 0 - 1
test/tooltest2.py

@@ -75,7 +75,6 @@ If no command is given, the whole suite of tests is run.
 	}
 }
 
-
 sample_text_hexdump = (
 	'000000: 5468 6520 5469 6d65 7320 3033 2f4a 616e{n}' +
 	'000010: 2f32 3030 3920 4368 616e 6365 6c6c 6f72{n}' +