diff --git a/data_files/mmgen.cfg b/data_files/mmgen.cfg index 9c07ac63..303e812f 100644 --- a/data_files/mmgen.cfg +++ b/data_files/mmgen.cfg @@ -82,19 +82,19 @@ ############################ # Ignore Bitcoin Core version: -# btc_ignore_daemon_version +# btc_ignore_daemon_version false # Ignore Litecoin Core version: -# ltc_ignore_daemon_version +# ltc_ignore_daemon_version false # Ignore Bitcoin Cash Node version: -# bch_ignore_daemon_version +# bch_ignore_daemon_version false # Ignore OpenEthereum version for ETH: -# eth_ignore_daemon_version +# eth_ignore_daemon_version false # Ignore OpenEthereum version for ETC: -# etc_ignore_daemon_version +# etc_ignore_daemon_version false ##################### ## Altcoin options ## diff --git a/mmgen/cfg.py b/mmgen/cfg.py index ab0d4670..93a7a4a2 100755 --- a/mmgen/cfg.py +++ b/mmgen/cfg.py @@ -128,20 +128,23 @@ class CfgFileSample(CfgFile): self.parse_var(' '.join(last_line[1:]),n) if parse_vars else None, ) - def get_chunks(lines): + def gen_chunks(lines): hdr = True chunk = [] in_chunk = False - for n,line in enumerate(lines,1): + + for lineno,line in enumerate(lines,1): + if line.startswith('##'): hdr = False continue + if hdr: continue if line == '': in_chunk = False - elif line.startswith('# '): + elif line.startswith('#'): if in_chunk == False: if chunk: yield process_chunk(chunk,last_nonblank) @@ -149,14 +152,14 @@ class CfgFileSample(CfgFile): in_chunk = True else: chunk.append(line) - last_nonblank = n + last_nonblank = lineno else: - die(2,'parse error in file {!r}, line {}'.format(self.fn,n)) + raise CfgFileParseError('Parse error in file {!r}, line {}'.format(self.fn,lineno)) if chunk: yield process_chunk(chunk,last_nonblank) - return list(get_chunks(self.data)) + return list(gen_chunks(self.data)) class CfgFileUsr(CfgFile): desc = 'user configuration file' diff --git a/mmgen/daemon.py b/mmgen/daemon.py index 25cb6916..3db5647e 100755 --- a/mmgen/daemon.py +++ b/mmgen/daemon.py @@ -95,7 +95,7 @@ class Daemon(MMGenObject): # TODO: assumes only one running instance of given daemon cp = self.run_cmd(['ps','-Wl'],silent=True,check=False) for line in cp.stdout.decode().splitlines(): - if self.exec_fn_mswin in line: + if f'{self.exec_fn}.exe' in line: return line.split()[3] # use Windows, not Cygwin, PID die(2,'PID for {!r} not found in ps output'.format(ss)) elif self.use_pidfile: @@ -125,7 +125,7 @@ class Daemon(MMGenObject): if not silent: m = '{} {} already running with pid {}' msg(m.format(self.net_desc,self.desc,self.pid)) - return + return True self.wait_for_state('stopped') @@ -162,6 +162,7 @@ class Daemon(MMGenObject): else: if not silent: msg('{} {} on port {} not running'.format(self.net_desc,self.desc,self.rpc_port)) + return True def restart(self,silent=False): self.stop(silent=silent) @@ -225,7 +226,6 @@ class MoneroWalletDaemon(Daemon): daemon_id = 'xmr' network = 'wallet RPC' new_console_mswin = True - exec_fn_mswin = 'monero-wallet-rpc.exe' ps_pid_mswin = True def __init__(self, wallet_dir, @@ -335,8 +335,8 @@ class CoinDaemon(Daemon): 'cls_pfx', 'coind_name', 'coind_version', 'coind_version_str', # latest tested version - 'coind_exec', - 'cli_exec', + 'exec_fn', + 'cli_fn', 'cfg_file', 'testnet_dir', 'dfl_rpc', @@ -444,7 +444,7 @@ class CoinDaemon(Daemon): else: network_id = network_id.lower() assert network_id in cls.network_ids, f'{network_id!r}: invalid network ID' - from mmgen.protocol import CoinProtocol + from .protocol import CoinProtocol daemon_id,network = CoinProtocol.Base.parse_network_id(network_id) me = Daemon.__new__(globals()[cls.daemon_ids[daemon_id].cls_pfx+'Daemon']) @@ -534,13 +534,13 @@ class CoinDaemon(Daemon): @property def start_cmd(self): - return ([self.coind_exec] + return ([self.exec_fn] + self.coind_args + self.shared_args + self.usr_coind_args ) def cli_cmd(self,*cmds): - return ([self.cli_exec] + return ([self.cli_fn] + self.shared_args + list(cmds) ) @@ -553,7 +553,7 @@ class BitcoinDaemon(CoinDaemon): if self.platform == 'win' and self.daemon_id == 'bch': self.use_pidfile = False - from mmgen.regtest import MMGenRegtest + from .regtest import MMGenRegtest self.shared_args = list_gen( [f'--datadir={self.datadir}'], [f'--rpcport={self.rpc_port}'], @@ -604,7 +604,6 @@ class BitcoinDaemon(CoinDaemon): class MoneroDaemon(CoinDaemon): - exec_fn_mswin = 'monerod.exe' ps_pid_mswin = True new_console_mswin = True host = 'localhost' # FIXME @@ -643,7 +642,7 @@ class MoneroDaemon(CoinDaemon): if not self.test_socket(self.host,self.rpc_port): return 'stopped' cp = self.run_cmd( - [self.coind_exec] + [self.exec_fn] + self.shared_args + ['status'], silent=True, @@ -655,11 +654,10 @@ class MoneroDaemon(CoinDaemon): if self.platform == 'win': return ['kill','-Wf',self.pid] else: - return [self.coind_exec] + self.shared_args + ['exit'] + return [self.exec_fn] + self.shared_args + ['exit'] class EthereumDaemon(CoinDaemon): - exec_fn_mswin = 'openethereum.exe' ps_pid_mswin = True def subclass_init(self): @@ -667,17 +665,20 @@ class EthereumDaemon(CoinDaemon): # linux: $HOME/.local/share/io.parity.ethereum/chains/DevelopmentChain # win: $LOCALAPPDATA/Parity/Ethereum/chains/DevelopmentChain - chaindir = os.path.join(self.datadir,'devchain') - shutil.rmtree(chaindir,ignore_errors=True) + base_path = os.path.join(self.datadir,'devchain') + shutil.rmtree(base_path,ignore_errors=True) ld = self.platform == 'linux' and not 'no_daemonize' in self.opts self.coind_args = list_gen( + ['--no-ws'], + ['--no-ipc'], + ['--no-secretstore'], [f'--ports-shift={self.port_shift}'], - [f'--base-path={chaindir}'], + [f'--base-path={base_path}'], ['--config=dev'], ['--mode=offline',self.test_suite], ['--log-file='+os.path.join(self.datadir,'openethereum.log')], - ['daemon', ld], + ['daemon', ld], [self.pidfile, ld], ) diff --git a/mmgen/help.py b/mmgen/help.py index a0a7b44c..1fe8ed57 100755 --- a/mmgen/help.py +++ b/mmgen/help.py @@ -35,7 +35,7 @@ def help_notes_func(proto,k): def coind_exec(): from .daemon import CoinDaemon return ( - CoinDaemon(proto.coin).coind_exec if proto.coin.lower() in CoinDaemon.daemon_ids else + CoinDaemon(proto.coin).exec_fn if proto.coin.lower() in CoinDaemon.coins else 'bitcoind' ) class help_notes: diff --git a/mmgen/tx.py b/mmgen/tx.py index 14ca2a03..ea78d46b 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -1226,7 +1226,7 @@ class MMGenTX: self.check_pubkey_scripts() - qmsg(f'Passing {len(keys)} key{suf(keys)} to {self.rpc.daemon.coind_exec}') + qmsg(f'Passing {len(keys)} key{suf(keys)} to {self.rpc.daemon.exec_fn}') if self.has_segwit_inputs(): from .addr import KeyGenerator,AddrGenerator diff --git a/scripts/uninstall-mmgen.py b/scripts/uninstall-mmgen.py index 4610cefd..9f505f5b 100755 --- a/scripts/uninstall-mmgen.py +++ b/scripts/uninstall-mmgen.py @@ -54,7 +54,11 @@ opts_data = { cmd_args = opts.init(opts_data) -if len(cmd_args): opts.usage() +if g.platform == 'linux' and os.getenv('USER') != 'root': + die(1,'This program must be run as root') + +if len(cmd_args): + opts.usage() mod_dir = os.path.split(normalize_path(modpath_save))[0] mod_pardir = os.path.split(mod_dir)[0] diff --git a/setup.py b/setup.py index d1ce0992..8b7e068b 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys,os,subprocess +import sys,os +from subprocess import run,PIPE from shutil import copy2 sys_ver = sys.version_info[:2] @@ -24,11 +25,13 @@ req_ver = (3,6) ver2f = lambda t: float('{}.{:03}'.format(*t)) if ver2f(sys_ver) < ver2f(req_ver): - m = '{}.{}: wrong Python version. MMGen requires Python {}.{} or greater\n' + m = '{}.{}: incorrect Python version. MMGen requires Python {}.{} or greater\n' sys.stderr.write(m.format(*sys_ver,*req_ver)) sys.exit(1) -have_msys2 = subprocess.check_output(['uname','-s']).strip()[:7] == b'MSYS_NT' +have_msys2 = run(['uname','-s'],stdout=PIPE,check=True).stdout.startswith(b'MSYS_NT') +if have_msys2: + print('MSYS2 system detected') from distutils.core import setup,Extension from distutils.command.build_ext import build_ext @@ -50,7 +53,7 @@ class my_build_ext(build_ext): ext_dest = os.path.join('mmgen',os.path.basename(ext_src)) try: os.unlink(ext_dest) except: pass - os.chmod(ext_src,0o755) + os.chmod(ext_src,0o755) # required if user has non-standard umask print('copying {} to {}'.format(ext_src,ext_dest)) copy2(ext_src,ext_dest) copy_owner(cwd,ext_dest) @@ -66,7 +69,7 @@ def link_or_copy(tdir,a,b): class my_install_data(install_data): def run(self): for f in 'mmgen.cfg','mnemonic.py','mn_wordlist.c': - os.chmod(os.path.join('data_files',f),0o644) + os.chmod(os.path.join('data_files',f),0o644) # required if user has non-standard umask install_data.run(self) class my_build_py(build_py): diff --git a/test/include/common.py b/test/include/common.py index ad9a0f50..6ed5f2ae 100755 --- a/test/include/common.py +++ b/test/include/common.py @@ -191,18 +191,19 @@ def stop_test_daemons(*network_ids): return test_daemons_ops(*network_ids,op='stop') def restart_test_daemons(*network_ids,remove_datadir=False): - stop_test_daemons(*network_ids) + if not stop_test_daemons(*network_ids): + return False return start_test_daemons(*network_ids,remove_datadir=remove_datadir) def test_daemons_ops(*network_ids,op,remove_datadir=False): if not opt.no_daemon_autostart: from mmgen.daemon import CoinDaemon silent = not opt.verbose and not getattr(opt,'exact_output',False) + ret = False for network_id in network_ids: - if network_id.lower() not in CoinDaemon.network_ids: # silently ignore invalid IDs - continue d = CoinDaemon(network_id,test_suite=True) if remove_datadir: d.stop(silent=True) d.remove_datadir() - d.cmd(op,silent=silent) + ret = d.cmd(op,silent=silent) + return ret diff --git a/test/misc/cfg.py b/test/misc/cfg.py index 30e454cf..f415bd92 100755 --- a/test/misc/cfg.py +++ b/test/misc/cfg.py @@ -6,21 +6,27 @@ from mmgen.common import * cmd_args = opts.init() from mmgen.cfg import cfg_file -cu = cfg_file('usr') -cS = cfg_file('sys') -cs = cfg_file('sample') -msg('usr cfg: {}'.format(cu.fn)) -msg('sys cfg: {}'.format(cS.fn)) -msg('sample cfg: {}'.format(cs.fn)) + +cf_usr = cfg_file('usr') +cf_sys = cfg_file('sys') +cf_sample = cfg_file('sample') + +msg('Usr cfg file: {}'.format(cf_usr.fn)) +msg('Sys cfg file: {}'.format(cf_sys.fn)) +msg('Sample cfg file: {}'.format(cf_sample.fn)) if cmd_args: if cmd_args[0] == 'parse_test': - ps = cs.parse(parse_vars=True) + ps = cf_sample.parse(parse_vars=True) msg('parsed chunks: {}'.format(len(ps))) - pu = cu.parse() + pu = cf_usr.parse() msg('usr cfg: {}'.format(' '.join(['{}={}'.format(i.name,i.value) for i in pu]))) elif cmd_args[0] == 'coin_specific_vars': from mmgen.protocol import init_proto_from_opts proto = init_proto_from_opts() for varname in cmd_args[1:]: - print(f'{type(proto).__name__}.{varname}:',getattr(proto,varname)) + print('{}.{}: {}'.format( + type(proto).__name__, + varname, + getattr(proto,varname) + )) diff --git a/test/start-coin-daemons.py b/test/start-coin-daemons.py index bbbd4fd2..9fa7cae8 100755 --- a/test/start-coin-daemons.py +++ b/test/start-coin-daemons.py @@ -5,6 +5,8 @@ from include.tests_header import repo_root from mmgen.common import * from mmgen.daemon import CoinDaemon +network_ids = CoinDaemon.network_ids + action = g.prog_name.split('-')[0] opts_data = { @@ -30,7 +32,7 @@ Valid network IDs: {nid}, all, or no_xmr }, 'code': { 'options': lambda s: s.format(a=action.capitalize(),pn=g.prog_name), - 'notes': lambda s: s.format(nid=', '.join(CoinDaemon.network_ids)) + 'notes': lambda s: s.format(nid=', '.join(network_ids)) } } @@ -40,7 +42,7 @@ if 'all' in cmd_args or 'no_xmr' in cmd_args: if len(cmd_args) != 1: die(1,"'all' or 'no_xmr' must be the sole argument") else: - ids = list(CoinDaemon.network_ids) + ids = list(network_ids) if cmd_args[0] == 'no_xmr': ids.remove('xmr') else: @@ -48,7 +50,7 @@ else: if not ids: opts.usage() for i in ids: - if i not in CoinDaemon.network_ids: + if i not in network_ids: die(1,f'{i!r}: invalid network ID') if 'eth' in ids and 'etc' in ids: @@ -63,7 +65,7 @@ for network_id in ids: opts = ['no_daemonize'] if opt.no_daemonize else None, port_shift = int(opt.port_shift or 0), datadir = opt.datadir ) - d.debug = opt.debug + d.debug = d.debug or opt.debug d.wait = not opt.no_wait if opt.get_state: print('{} {} (port {}) is {}'.format(d.net_desc,d.desc,d.rpc_port,d.state)) diff --git a/test/test_py_d/ts_cfg.py b/test/test_py_d/ts_cfg.py index 1d409332..7a07c38d 100755 --- a/test/test_py_d/ts_cfg.py +++ b/test/test_py_d/ts_cfg.py @@ -60,7 +60,7 @@ class TestSuiteCfg(TestSuiteBase): for i in (1,2,3,4,5): t.expect(errstr) for k in ('usr','sys','sample'): - t.expect('{} cfg: {}'.format(k,self.path(k))) + t.expect('{} cfg file:\s+{}'.format(capfirst(k),self.path(k)),regex=True) assert not os.path.exists(self.path(k)), self.path(k) t.read() return t