Browse Source

minor fixes and cleanups

The MMGen Project 3 years ago
parent
commit
bab1242817
11 changed files with 74 additions and 54 deletions
  1. 5 5
      data_files/mmgen.cfg
  2. 9 6
      mmgen/cfg.py
  3. 18 17
      mmgen/daemon.py
  4. 1 1
      mmgen/help.py
  5. 1 1
      mmgen/tx.py
  6. 5 1
      scripts/uninstall-mmgen.py
  7. 8 5
      setup.py
  8. 5 4
      test/include/common.py
  9. 15 9
      test/misc/cfg.py
  10. 6 4
      test/start-coin-daemons.py
  11. 1 1
      test/test_py_d/ts_cfg.py

+ 5 - 5
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 ##

+ 9 - 6
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'

+ 18 - 17
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],
 		)
 

+ 1 - 1
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:

+ 1 - 1
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

+ 5 - 1
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]

+ 8 - 5
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 <http://www.gnu.org/licenses/>.
 
-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):

+ 5 - 4
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

+ 15 - 9
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)
+			))

+ 6 - 4
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))

+ 1 - 1
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