diff --git a/data_files/mmgen.cfg b/data_files/mmgen.cfg index 085faba6..2bc4c629 100644 --- a/data_files/mmgen.cfg +++ b/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 # ##################################################################### diff --git a/mmgen/addr.py b/mmgen/addr.py index 391fec47..49ab68c8 100755 --- a/mmgen/addr.py +++ b/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 = '' diff --git a/mmgen/baseconv.py b/mmgen/baseconv.py index 81d35e18..4dfa62e2 100755 --- a/mmgen/baseconv.py +++ b/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 diff --git a/mmgen/daemon.py b/mmgen/daemon.py index 507b4c07..0c9db956 100755 --- a/mmgen/daemon.py +++ b/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: diff --git a/mmgen/main_autosign.py b/mmgen/main_autosign.py index 99570bae..3fd2e1ff 100755 --- a/mmgen/main_autosign.py +++ b/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'] diff --git a/mmgen/mn_electrum.py b/mmgen/mn_electrum.py index 92dbe5f6..086ed38e 100755 --- a/mmgen/mn_electrum.py +++ b/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 . + # ------------------------------------------------------------------------------ + # 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 diff --git a/mmgen/obj.py b/mmgen/obj.py index c96cf9d0..fca7a275 100755 --- a/mmgen/obj.py +++ b/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 diff --git a/mmgen/rpc.py b/mmgen/rpc.py index e35990c6..ea616a9e 100755 --- a/mmgen/rpc.py +++ b/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 diff --git a/mmgen/tool.py b/mmgen/tool.py index f2828ad7..a6858cb1 100755 --- a/mmgen/tool.py +++ b/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" diff --git a/test/scrambletest.py b/test/scrambletest.py index a963c6d9..c37177e5 100755 --- a/test/scrambletest.py +++ b/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}' diff --git a/test/test.py b/test/test.py index a32dffe3..e95ff0a6 100755 --- a/test/test.py +++ b/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]])) ) diff --git a/test/test_py_d/ts_ref_3seed.py b/test/test_py_d/ts_ref_3seed.py index cf77e82b..3fb25242 100755 --- a/test/test_py_d/ts_ref_3seed.py +++ b/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') diff --git a/test/tooltest2.py b/test/tooltest2.py index 463838b3..7c69244b 100755 --- a/test/tooltest2.py +++ b/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}' +