Browse Source

globalvars.py: new GlobalConstants (gc), GlobalVars (gv) classes

- The attributes of GlobalConstants are non-configurable.  They’re constant
  for a given machine, user, executable and MMGen release.

- The attributes of GlobalVars, `stderr` and `stdout`, are used by the test
  suite to redirect msg() and friends to /dev/null.

- All the aforementioned attributes formerly belonged to GlobalConfig.
The MMGen Project 2 years ago
parent
commit
c3ce1ab8e3
70 changed files with 309 additions and 282 deletions
  1. 3 3
      mmgen/addrdata.py
  2. 2 2
      mmgen/addrfile.py
  3. 4 4
      mmgen/altcoin.py
  4. 2 2
      mmgen/cfgfile.py
  5. 2 2
      mmgen/color.py
  6. 4 4
      mmgen/crypto.py
  7. 3 3
      mmgen/daemon.py
  8. 2 2
      mmgen/filename.py
  9. 3 3
      mmgen/fileutil.py
  10. 76 61
      mmgen/globalvars.py
  11. 9 9
      mmgen/help.py
  12. 2 2
      mmgen/main.py
  13. 6 5
      mmgen/main_addrgen.py
  14. 5 5
      mmgen/main_addrimport.py
  15. 11 9
      mmgen/main_passgen.py
  16. 2 2
      mmgen/main_regtest.py
  17. 3 2
      mmgen/main_seedjoin.py
  18. 3 3
      mmgen/main_split.py
  19. 7 7
      mmgen/main_tool.py
  20. 7 7
      mmgen/main_txbump.py
  21. 2 2
      mmgen/main_txcreate.py
  22. 4 4
      mmgen/main_txdo.py
  23. 2 2
      mmgen/main_txsend.py
  24. 6 6
      mmgen/main_txsign.py
  25. 6 5
      mmgen/main_wallet.py
  26. 2 1
      mmgen/main_xmrwallet.py
  27. 2 2
      mmgen/msg.py
  28. 10 10
      mmgen/opts.py
  29. 4 4
      mmgen/proto/btc/daemon.py
  30. 4 4
      mmgen/proto/eth/daemon.py
  31. 2 2
      mmgen/proto/xmr/daemon.py
  32. 6 6
      mmgen/protocol.py
  33. 2 2
      mmgen/rpc.py
  34. 4 2
      mmgen/term.py
  35. 2 2
      mmgen/tool/fileutil.py
  36. 2 2
      mmgen/tool/help.py
  37. 2 2
      mmgen/tool/util.py
  38. 2 1
      mmgen/tw/unspent.py
  39. 2 1
      mmgen/tw/view.py
  40. 3 3
      mmgen/tx/base.py
  41. 2 2
      mmgen/tx/info.py
  42. 4 3
      mmgen/tx/new.py
  43. 4 4
      mmgen/tx/sign.py
  44. 2 2
      mmgen/ui.py
  45. 13 13
      mmgen/util.py
  46. 2 2
      mmgen/wallet/enc.py
  47. 3 3
      mmgen/wallet/incog_hidden.py
  48. 2 2
      scripts/uninstall-mmgen.py
  49. 2 2
      test/gentest.py
  50. 2 2
      test/include/coin_daemon_control.py
  51. 4 4
      test/include/common.py
  52. 1 1
      test/misc/get_passphrase.py
  53. 5 5
      test/misc/term.py
  54. 1 1
      test/scrambletest.py
  55. 6 6
      test/test.py
  56. 4 3
      test/test_py_d/common.py
  57. 3 3
      test/test_py_d/ts_autosign.py
  58. 2 2
      test/test_py_d/ts_base.py
  59. 1 1
      test/test_py_d/ts_cfgfile.py
  60. 2 2
      test/test_py_d/ts_ethdev.py
  61. 4 4
      test/test_py_d/ts_input.py
  62. 2 2
      test/test_py_d/ts_misc.py
  63. 1 1
      test/test_py_d/ts_tool.py
  64. 2 2
      test/test_py_d/ts_xmrwallet.py
  65. 1 1
      test/tooltest.py
  66. 2 2
      test/tooltest2.py
  67. 1 1
      test/unit_tests.py
  68. 4 4
      test/unit_tests_d/__init__.py
  69. 1 1
      test/unit_tests_d/ut_rpc.py
  70. 1 1
      test/unit_tests_d/ut_testdep.py

+ 3 - 3
mmgen/addrdata.py

@@ -74,7 +74,7 @@ class TwAddrData(AddrData,metaclass=AsyncInit):
 	async def __init__(self,proto,twctl=None):
 	async def __init__(self,proto,twctl=None):
 		from .rpc import rpc_init
 		from .rpc import rpc_init
 		from .tw.shared import TwLabel
 		from .tw.shared import TwLabel
-		from .globalvars import g
+		from .globalvars import gc
 		from .seed import SeedID
 		from .seed import SeedID
 		self.proto = proto
 		self.proto = proto
 		self.rpc = await rpc_init(proto)
 		self.rpc = await rpc_init(proto)
@@ -86,7 +86,7 @@ class TwAddrData(AddrData,metaclass=AsyncInit):
 			if l and l.mmid.type == 'mmgen':
 			if l and l.mmid.type == 'mmgen':
 				obj = l.mmid.obj
 				obj = l.mmid.obj
 				if len(addr_array) != 1:
 				if len(addr_array) != 1:
-					message = self.msgs['multiple_acct_addrs'].strip().format( acct=acct, proj=g.proj_name )
+					message = self.msgs['multiple_acct_addrs'].strip().format( acct=acct, proj=gc.proj_name )
 					die(3, fmt( message, indent='  ' ))
 					die(3, fmt( message, indent='  ' ))
 				al_id = AddrListID(
 				al_id = AddrListID(
 					sid = SeedID(sid=obj.sid),
 					sid = SeedID(sid=obj.sid),
@@ -96,7 +96,7 @@ class TwAddrData(AddrData,metaclass=AsyncInit):
 				out[al_id].append(AddrListEntry(self.proto,idx=obj.idx,addr=addr_array[0],comment=l.comment))
 				out[al_id].append(AddrListEntry(self.proto,idx=obj.idx,addr=addr_array[0],comment=l.comment))
 				i += 1
 				i += 1
 
 
-		vmsg(f'{i} {g.proj_name} addresses found, {len(twd)} accounts total')
+		vmsg(f'{i} {gc.proj_name} addresses found, {len(twd)} accounts total')
 
 
 		for al_id in out:
 		for al_id in out:
 			self.add(AddrList(
 			self.add(AddrList(

+ 2 - 2
mmgen/addrfile.py

@@ -87,8 +87,8 @@ class AddrFile(MMGenObject):
 			self.file_header_mn.format(p.pw_fmt.upper())
 			self.file_header_mn.format(p.pw_fmt.upper())
 				if p.gen_passwds and p.pw_fmt in ('bip39','xmrseed') else
 				if p.gen_passwds and p.pw_fmt in ('bip39','xmrseed') else
 			self.file_header ).strip()
 			self.file_header ).strip()
-		from .globalvars import g
-		out = [fh.format(pnm=g.proj_name,n=TwComment.max_screen_width) + '\n']
+		from .globalvars import gc
+		out = [fh.format(pnm=gc.proj_name,n=TwComment.max_screen_width) + '\n']
 
 
 		if p.chksum:
 		if p.chksum:
 			out.append(f'# {capfirst(p.desc)} data checksum for {p.id_str}: {p.chksum}')
 			out.append(f'# {capfirst(p.desc)} data checksum for {p.id_str}: {p.chksum}')

+ 4 - 4
mmgen/altcoin.py

@@ -36,6 +36,8 @@ altcoin.py - Coin constants for Bitcoin-derived altcoins
 #   NBT:  150/191 c/u,  25/('B'),  26/('B')
 #   NBT:  150/191 c/u,  25/('B'),  26/('B')
 
 
 import sys
 import sys
+
+from .globalvars import gc
 from .util import msg
 from .util import msg
 
 
 def test_equal(desc,a,b,*cdata):
 def test_equal(desc,a,b,*cdata):
@@ -434,10 +436,9 @@ class CoinInfo(object):
 	@classmethod
 	@classmethod
 	def verify_core_coin_data(cls,quiet=False,verbose=False):
 	def verify_core_coin_data(cls,quiet=False,verbose=False):
 		from .protocol import CoinProtocol,init_proto
 		from .protocol import CoinProtocol,init_proto
-		from .globalvars import g
 
 
 		for network in ('mainnet','testnet'):
 		for network in ('mainnet','testnet'):
-			for coin in g.core_coins:
+			for coin in gc.core_coins:
 				e = cls.get_entry(coin,network)
 				e = cls.get_entry(coin,network)
 				if e:
 				if e:
 					proto = init_proto(coin,testnet=network=='testnet')
 					proto = init_proto(coin,testnet=network=='testnet')
@@ -718,8 +719,7 @@ def init_genonly_altcoins(usr_coin=None,testnet=False):
 			data[network] = CoinInfo.get_supported_coins(network)
 			data[network] = CoinInfo.get_supported_coins(network)
 		trust_level = 0
 		trust_level = 0
 	else:
 	else:
-		from .globalvars import g
-		if usr_coin.lower() in g.core_coins: # core coin, so return immediately
+		if usr_coin.lower() in gc.core_coins: # core coin, so return immediately
 			from .protocol import CoinProtocol
 			from .protocol import CoinProtocol
 			return CoinProtocol.coins[usr_coin.lower()].trust_level
 			return CoinProtocol.coins[usr_coin.lower()].trust_level
 		for network in networks:
 		for network in networks:

+ 2 - 2
mmgen/cfgfile.py

@@ -23,7 +23,7 @@ cfgfile: API for the MMGen runtime configuration file and related files
 import os,re
 import os,re
 from collections import namedtuple
 from collections import namedtuple
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .util import msg,ymsg,suf,fmt,fmt_list,oneshot_warning,strip_comment,capfirst
 from .util import msg,ymsg,suf,fmt,fmt_list,oneshot_warning,strip_comment,capfirst
 
 
 def mmgen_cfg_file(id_str):
 def mmgen_cfg_file(id_str):
@@ -187,7 +187,7 @@ class CfgFileSampleSys(cfg_file_sample):
 		else:
 		else:
 			# self.fn is used for error msgs only, so file need not exist on filesystem
 			# self.fn is used for error msgs only, so file need not exist on filesystem
 			self.fn = os.path.join(os.path.dirname(__file__),'data',self.fn_base)
 			self.fn = os.path.join(os.path.dirname(__file__),'data',self.fn_base)
-			self.data = g.get_mmgen_data_file(self.fn_base).splitlines()
+			self.data = gc.get_mmgen_data_file(self.fn_base).splitlines()
 
 
 	def make_metadata(self):
 	def make_metadata(self):
 		return [f'# Version {self.cur_ver} {self.computed_chksum}']
 		return [f'# Version {self.cur_ver} {self.computed_chksum}']

+ 2 - 2
mmgen/color.py

@@ -47,8 +47,8 @@ def nocolor(s):
 
 
 def set_vt100():
 def set_vt100():
 	'hack to put term into VT100 mode under MSWin'
 	'hack to put term into VT100 mode under MSWin'
-	from .globalvars import g
-	if g.platform == 'win':
+	from .globalvars import gc
+	if gc.platform == 'win':
 		from subprocess import run
 		from subprocess import run
 		run([],shell=True)
 		run([],shell=True)
 
 

+ 4 - 4
mmgen/crypto.py

@@ -23,7 +23,7 @@ crypto: Random number, password hashing and symmetric encryption routines for th
 import os
 import os
 from collections import namedtuple
 from collections import namedtuple
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import (
 from .util import (
 	msg,
 	msg,
@@ -244,7 +244,7 @@ class Crypto:
 
 
 		avg_prec = sum(len(t.split('.')[1]) for t in time_data) // len(time_data)
 		avg_prec = sum(len(t.split('.')[1]) for t in time_data) // len(time_data)
 
 
-		if avg_prec < g.min_time_precision:
+		if avg_prec < gc.min_time_precision:
 			ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points. User entropy quality is degraded!')
 			ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points. User entropy quality is degraded!')
 
 
 		ret = key_data + '\n' + '\n'.join(time_data)
 		ret = key_data + '\n' + '\n'.join(time_data)
@@ -300,7 +300,7 @@ class Crypto:
 
 
 	def get_hash_preset_from_user(
 	def get_hash_preset_from_user(
 			self,
 			self,
-			old_preset = g.dfl_hash_preset,
+			old_preset = gc.dfl_hash_preset,
 			data_desc  = 'data',
 			data_desc  = 'data',
 			prompt     = None ):
 			prompt     = None ):
 
 
@@ -338,7 +338,7 @@ class Crypto:
 			if opt.echo_passphrase:
 			if opt.echo_passphrase:
 				pw = ' '.join(get_words_from_user( f'Enter {pw_desc} for {data_desc}: ' ))
 				pw = ' '.join(get_words_from_user( f'Enter {pw_desc} for {data_desc}: ' ))
 			else:
 			else:
-				for i in range(g.passwd_max_tries):
+				for i in range(gc.passwd_max_tries):
 					pw = ' '.join(get_words_from_user( f'Enter {pw_desc} for {data_desc}: ' ))
 					pw = ' '.join(get_words_from_user( f'Enter {pw_desc} for {data_desc}: ' ))
 					pw_chk = ' '.join(get_words_from_user( f'Repeat {pw_desc}: ' ))
 					pw_chk = ' '.join(get_words_from_user( f'Repeat {pw_desc}: ' ))
 					dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
 					dmsg(f'Passphrases: [{pw}] [{pw_chk}]')

+ 3 - 3
mmgen/daemon.py

@@ -24,7 +24,7 @@ import os,time,importlib
 from subprocess import run,PIPE,CompletedProcess
 from subprocess import run,PIPE,CompletedProcess
 from collections import namedtuple
 from collections import namedtuple
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .color import set_vt100
 from .color import set_vt100
 from .util import msg,Msg_r,ymsg,die,remove_dups,oneshot_warning
 from .util import msg,Msg_r,ymsg,die,remove_dups,oneshot_warning
 from .flags import *
 from .flags import *
@@ -51,7 +51,7 @@ class Daemon(Lockable):
 
 
 	def __init__(self,opts=None,flags=None):
 	def __init__(self,opts=None,flags=None):
 
 
-		self.platform = g.platform
+		self.platform = gc.platform
 		if self.platform == 'win':
 		if self.platform == 'win':
 			self.use_pidfile = False
 			self.use_pidfile = False
 			self.use_threads = True
 			self.use_threads = True
@@ -478,7 +478,7 @@ class CoinDaemon(Daemon):
 		assert self.test_suite, 'datadir removal restricted to test suite'
 		assert self.test_suite, 'datadir removal restricted to test suite'
 		if self.state == 'stopped':
 		if self.state == 'stopped':
 			run([
 			run([
-				('rm' if g.platform == 'win' else '/bin/rm'),
+				('rm' if gc.platform == 'win' else '/bin/rm'),
 				'-rf',
 				'-rf',
 				self.datadir ])
 				self.datadir ])
 			set_vt100()
 			set_vt100()

+ 2 - 2
mmgen/filename.py

@@ -43,8 +43,8 @@ class File:
 		import stat
 		import stat
 		if stat.S_ISBLK(st.st_mode):
 		if stat.S_ISBLK(st.st_mode):
 			mode = (os.O_RDONLY,os.O_RDWR)[bool(write)]
 			mode = (os.O_RDONLY,os.O_RDWR)[bool(write)]
-			from .globalvars import g
-			if g.platform == 'win':
+			from .globalvars import gc
+			if gc.platform == 'win':
 				mode |= os.O_BINARY
 				mode |= os.O_BINARY
 			try:
 			try:
 				fd = os.open(fn, mode)
 				fd = os.open(fn, mode)

+ 3 - 3
mmgen/fileutil.py

@@ -22,7 +22,7 @@ fileutil: Routines that read, write, execute or stat files
 
 
 import sys,os
 import sys,os
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .color import set_vt100
 from .color import set_vt100
 from .util import (
 from .util import (
 	msg,
 	msg,
@@ -43,7 +43,7 @@ def check_or_create_dir(path):
 		if os.getenv('MMGEN_TEST_SUITE'):
 		if os.getenv('MMGEN_TEST_SUITE'):
 			from subprocess import run
 			from subprocess import run
 			run([
 			run([
-				('rm' if g.platform == 'win' else '/bin/rm'),
+				('rm' if gc.platform == 'win' else '/bin/rm'),
 				'-rf',
 				'-rf',
 				path ])
 				path ])
 			set_vt100()
 			set_vt100()
@@ -205,7 +205,7 @@ def write_data_to_file(
 			else:
 			else:
 				msg('Redirecting output to file')
 				msg('Redirecting output to file')
 
 
-		if binary and g.platform == 'win':
+		if binary and gc.platform == 'win':
 			import msvcrt
 			import msvcrt
 			msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)
 			msvcrt.setmode(sys.stdout.fileno(),os.O_BINARY)
 
 

+ 76 - 61
mmgen/globalvars.py

@@ -29,6 +29,79 @@ def die(exit_val,s=''):
 		sys.stderr.write(s+'\n')
 		sys.stderr.write(s+'\n')
 	sys.exit(exit_val)
 	sys.exit(exit_val)
 
 
+class GlobalConstants(Lockable):
+	"""
+	These values are non-configurable.  They’re constant for a given machine,
+	user, executable and MMGen release.
+	"""
+	proj_name          = 'MMGen'
+	proj_url           = 'https://github.com/mmgen/mmgen'
+	author             = 'The MMGen Project'
+	email              = '<mmgen@tuta.io>'
+	Cdates             = '2013-2023'
+	dfl_hash_preset    = '3'
+	passwd_max_tries   = 5
+	min_screen_width   = 80
+	min_time_precision = 18
+
+	# must match CoinProtocol.coins
+	core_coins = ('btc','bch','ltc','eth','etc','zec','xmr')
+
+	prog_name = os.path.basename(sys.argv[0])
+	is_txprog = prog_name == 'mmgen-regtest' or prog_name.startswith('mmgen-tx')
+
+	for k in ('linux','win','msys'):
+		if sys.platform.startswith(k):
+			platform = { 'linux':'linux', 'win':'win', 'msys':'win' }[k]
+			break
+	else:
+		die(1,f'{sys.platform!r}: platform not supported by {proj_name}')
+
+	if os.getenv('HOME'):   # Linux or MSYS2
+		home_dir = os.getenv('HOME')
+	elif platform == 'win': # Windows without MSYS2 - not supported
+		die(1,f'$HOME not set!  {proj_name} for Windows must be run in MSYS2 environment')
+	else:
+		die(2,'$HOME is not set!  Unable to determine home directory')
+
+	def get_mmgen_data_file(self,filename,package='mmgen'):
+		"""
+		this is an expensive import, so do only when required
+		"""
+		# Resource will be unpacked and then cleaned up if necessary, see:
+		#    https://docs.python.org/3/library/importlib.html:
+		#        Note: This module provides functionality similar to pkg_resources Basic
+		#        Resource Access without the performance overhead of that package.
+		#    https://importlib-resources.readthedocs.io/en/latest/migration.html
+		#    https://setuptools.readthedocs.io/en/latest/pkg_resources.html
+		try:
+			from importlib.resources import files # Python 3.9
+		except ImportError:
+			from importlib_resources import files
+		return files(package).joinpath('data',filename).read_text()
+
+	@property
+	def version(self):
+		return self.get_mmgen_data_file(
+				filename = 'version',
+				package  = 'mmgen_node_tools' if self.prog_name.startswith('mmnode-') else 'mmgen'
+			).strip()
+
+	@property
+	def release_date(self):
+		return self.get_mmgen_data_file(filename='release_date').strip()
+
+gc = GlobalConstants()
+
+class GlobalVars:
+	"""
+	These are used only by the test suite to redirect msg() and friends to /dev/null
+	"""
+	stdout = sys.stdout
+	stderr = sys.stderr
+
+gv = GlobalVars()
+
 class GlobalConfig(Lockable):
 class GlobalConfig(Lockable):
 	"""
 	"""
 	Set global vars to default values
 	Set global vars to default values
@@ -44,15 +117,6 @@ class GlobalConfig(Lockable):
 
 
 	# Constants:
 	# Constants:
 
 
-	proj_name = 'MMGen'
-	proj_url  = 'https://github.com/mmgen/mmgen'
-	prog_name = os.path.basename(sys.argv[0])
-	author    = 'The MMGen Project'
-	email     = '<mmgen@tuta.io>'
-	Cdates    = '2013-2023'
-
-	is_txprog = prog_name == 'mmgen-regtest' or prog_name.startswith('mmgen-tx')
-
 	stdin_tty = sys.stdin.isatty()
 	stdin_tty = sys.stdin.isatty()
 	stdout = sys.stdout
 	stdout = sys.stdout
 	stderr = sys.stderr
 	stderr = sys.stderr
@@ -60,11 +124,9 @@ class GlobalConfig(Lockable):
 	http_timeout = 60
 	http_timeout = 60
 	err_disp_timeout = 0.7
 	err_disp_timeout = 0.7
 	short_disp_timeout = 0.3
 	short_disp_timeout = 0.3
-	min_time_precision = 18
 
 
 	# Variables - these might be altered at runtime:
 	# Variables - these might be altered at runtime:
 
 
-	dfl_hash_preset = '3'
 	usr_randchars   = 30
 	usr_randchars   = 30
 
 
 	fee_adjust = 1.0
 	fee_adjust = 1.0
@@ -134,27 +196,10 @@ class GlobalConfig(Lockable):
 		os.getenv('MMGEN_FORCE_COLOR')
 		os.getenv('MMGEN_FORCE_COLOR')
 	)
 	)
 
 
-	for k in ('linux','win','msys'):
-		if sys.platform.startswith(k):
-			platform = { 'linux':'linux', 'win':'win', 'msys':'win' }[k]
-			break
-	else:
-		die(1,f'{sys.platform!r}: platform not supported by {proj_name}')
-
-	if os.getenv('HOME'):   # Linux or MSYS2
-		home_dir = os.getenv('HOME')
-	elif platform == 'win': # Windows without MSYS2 - not supported
-		die(1,f'$HOME not set!  {proj_name} for Windows must be run in MSYS2 environment')
-	else:
-		die(2,'$HOME is not set!  Unable to determine home directory')
-
 	daemon_data_dir = '' # set by user
 	daemon_data_dir = '' # set by user
 	daemon_id = ''
 	daemon_id = ''
 	blacklisted_daemons = ''
 	blacklisted_daemons = ''
 
 
-	# must match CoinProtocol.coins
-	core_coins = ('btc','bch','ltc','eth','etc','zec','xmr')
-
 	# global var sets user opt:
 	# global var sets user opt:
 	global_sets_opt = (
 	global_sets_opt = (
 		'autochg_ignore_labels',
 		'autochg_ignore_labels',
@@ -297,7 +342,7 @@ class GlobalConfig(Lockable):
 		'fee_estimate_mode': _ov('nocase_pfx', ['conservative','economical']),
 		'fee_estimate_mode': _ov('nocase_pfx', ['conservative','economical']),
 		'rpc_backend':       _ov('nocase_pfx', ['auto','httplib','curl','aiohttp','requests']),
 		'rpc_backend':       _ov('nocase_pfx', ['auto','httplib','curl','aiohttp','requests']),
 	}
 	}
-	if platform == 'win':
+	if gc.platform == 'win':
 		_skip_type_check = ('stdout','stderr')
 		_skip_type_check = ('stdout','stderr')
 
 
 	auto_typeset_opts = {
 	auto_typeset_opts = {
@@ -306,13 +351,10 @@ class GlobalConfig(Lockable):
 		'vsize_adj': float,
 		'vsize_adj': float,
 	}
 	}
 
 
-	min_screen_width = 80
 	minconf = 1
 	minconf = 1
 	max_tx_file_size = 100000
 	max_tx_file_size = 100000
 	max_input_size   = 1024 * 1024
 	max_input_size   = 1024 * 1024
 
 
-	passwd_max_tries = 5
-
 	max_urandchars = 80
 	max_urandchars = 80
 	min_urandchars = 10
 	min_urandchars = 10
 
 
@@ -324,7 +366,7 @@ class GlobalConfig(Lockable):
 		short_disp_timeout = 0.1
 		short_disp_timeout = 0.1
 		if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
 		if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
 			stdin_tty = True
 			stdin_tty = True
-		if prog_name == 'unit_tests.py':
+		if gc.prog_name == 'unit_tests.py':
 			_set_ok += ('debug_subseed',)
 			_set_ok += ('debug_subseed',)
 			_reset_ok += ('force_standalone_scrypt_module',)
 			_reset_ok += ('force_standalone_scrypt_module',)
 
 
@@ -333,33 +375,6 @@ class GlobalConfig(Lockable):
 			if name[:11] == 'MMGEN_DEBUG':
 			if name[:11] == 'MMGEN_DEBUG':
 				os.environ[name] = '1'
 				os.environ[name] = '1'
 
 
-	def get_mmgen_data_file(self,filename,package='mmgen'):
-		"""
-		this is an expensive import, so do only when required
-		"""
-		# Resource will be unpacked and then cleaned up if necessary, see:
-		#    https://docs.python.org/3/library/importlib.html:
-		#        Note: This module provides functionality similar to pkg_resources Basic
-		#        Resource Access without the performance overhead of that package.
-		#    https://importlib-resources.readthedocs.io/en/latest/migration.html
-		#    https://setuptools.readthedocs.io/en/latest/pkg_resources.html
-		try:
-			from importlib.resources import files # Python 3.9
-		except ImportError:
-			from importlib_resources import files
-		return files(package).joinpath('data',filename).read_text()
-
-	@property
-	def version(self):
-		return self.get_mmgen_data_file(
-				filename = 'version',
-				package  = 'mmgen_node_tools' if self.prog_name.startswith('mmnode-') else 'mmgen'
-			).strip()
-
-	@property
-	def release_date(self):
-		return self.get_mmgen_data_file(filename='release_date').strip()
-
 	@property
 	@property
 	def data_dir_root(self):
 	def data_dir_root(self):
 		"""
 		"""
@@ -374,7 +389,7 @@ class GlobalConfig(Lockable):
 				from test.include.common import get_test_data_dir
 				from test.include.common import get_test_data_dir
 				self._data_dir_root = get_test_data_dir()
 				self._data_dir_root = get_test_data_dir()
 			else:
 			else:
-				self._data_dir_root = os.path.join(self.home_dir,'.'+self.proj_name.lower())
+				self._data_dir_root = os.path.join(gc.home_dir,'.'+gc.proj_name.lower())
 			return self._data_dir_root
 			return self._data_dir_root
 
 
 	@property
 	@property

+ 9 - 9
mmgen/help.py

@@ -20,7 +20,7 @@
 help: help notes for MMGen suite commands
 help: help notes for MMGen suite commands
 """
 """
 
 
-from .globalvars import g
+from .globalvars import gc
 
 
 def help_notes_func(proto,opt,k):
 def help_notes_func(proto,opt,k):
 
 
@@ -156,30 +156,30 @@ EXAMPLES:
   Send 0.123 {proto.coin} to an external {proto.name} address, returning the change to a
   Send 0.123 {proto.coin} to an external {proto.name} address, returning the change to a
   specific MMGen address in the tracking wallet:
   specific MMGen address in the tracking wallet:
 
 
-    $ {g.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}:7
+    $ {gc.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}:7
 
 
   Same as above, but select the change address automatically:
   Same as above, but select the change address automatically:
 
 
-    $ {g.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}
+    $ {gc.prog_name} {sample_addr},0.123 01ABCDEF:{mmtype}
 
 
   Same as above, but select the change address automatically by address type:
   Same as above, but select the change address automatically by address type:
 
 
-    $ {g.prog_name} {sample_addr},0.123 {mmtype}
+    $ {gc.prog_name} {sample_addr},0.123 {mmtype}
 
 
   Same as above, but reduce verbosity and specify fee of 20 satoshis
   Same as above, but reduce verbosity and specify fee of 20 satoshis
   per byte:
   per byte:
 
 
-    $ {g.prog_name} -q -f 20s {sample_addr},0.123 {mmtype}
+    $ {gc.prog_name} -q -f 20s {sample_addr},0.123 {mmtype}
 
 
   Send entire balance of selected inputs minus fee to an external {proto.name}
   Send entire balance of selected inputs minus fee to an external {proto.name}
   address:
   address:
 
 
-    $ {g.prog_name} {sample_addr}
+    $ {gc.prog_name} {sample_addr}
 
 
   Send entire balance of selected inputs minus fee to first unused wallet
   Send entire balance of selected inputs minus fee to first unused wallet
   address of specified type:
   address of specified type:
 
 
-    $ {g.prog_name} {mmtype}
+    $ {gc.prog_name} {mmtype}
 """
 """
 
 
 		def txcreate():
 		def txcreate():
@@ -235,9 +235,9 @@ must also be supplied on the command line if the data can't be found in the
 default wallet.
 default wallet.
 """.format(
 """.format(
 	wd  = (f'{coind_exec()} wallet dump or ' if isinstance(proto,mainnet) else ''),
 	wd  = (f'{coind_exec()} wallet dump or ' if isinstance(proto,mainnet) else ''),
-	pnm = g.proj_name,
+	pnm = gc.proj_name,
 	pnu = proto.name,
 	pnu = proto.name,
-	pnl = g.proj_name.lower() )
+	pnl = gc.proj_name.lower() )
 
 
 		def seedsplit():
 		def seedsplit():
 			from .seedsplit import SeedShareIdx,SeedShareCount,MasterShareIdx
 			from .seedsplit import SeedShareIdx,SeedShareCount,MasterShareIdx

+ 2 - 2
mmgen/main.py

@@ -29,9 +29,9 @@ def launch(mod,package='mmgen'):
 		mod = 'addrgen'
 		mod = 'addrgen'
 
 
 	import sys,os
 	import sys,os
-	from .globalvars import g
+	from .globalvars import gc
 
 
-	if g.platform == 'linux' and sys.stdin.isatty():
+	if gc.platform == 'linux' and sys.stdin.isatty():
 		import termios,atexit
 		import termios,atexit
 		fd = sys.stdin.fileno()
 		fd = sys.stdin.fileno()
 		old = termios.tcgetattr(fd)
 		old = termios.tcgetattr(fd)

+ 6 - 5
mmgen/main_addrgen.py

@@ -22,7 +22,7 @@ mmgen-addrgen: Generate a series or range of addresses from an MMGen
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .addr import MMGenAddrType
 from .addr import MMGenAddrType
 from .addrfile import AddrFile
 from .addrfile import AddrFile
@@ -30,7 +30,7 @@ from .wallet import Wallet
 
 
 import mmgen.addrlist
 import mmgen.addrlist
 
 
-if g.prog_name == 'mmgen-keygen':
+if gc.prog_name == 'mmgen-keygen':
 	gen_what = 'keys'
 	gen_what = 'keys'
 	gen_clsname = 'KeyAddrList'
 	gen_clsname = 'KeyAddrList'
 	gen_desc = 'secret keys'
 	gen_desc = 'secret keys'
@@ -49,7 +49,7 @@ opts_data = {
 		'desc': """
 		'desc': """
                  Generate a range or list of {desc} from an {pnm} wallet,
                  Generate a range or list of {desc} from an {pnm} wallet,
                  mnemonic, seed or brainwallet
                  mnemonic, seed or brainwallet
-			  """.format(desc=gen_desc,pnm=g.proj_name),
+			  """.format(desc=gen_desc,pnm=gc.proj_name),
 		'usage':'[opts] [seed source] <index list or range(s)>',
 		'usage':'[opts] [seed source] <index list or range(s)>',
 		'options': """
 		'options': """
 -h, --help            Print this help message
 -h, --help            Print this help message
@@ -69,7 +69,7 @@ opts_data = {
                       is required only for brainwallet and incognito inputs
                       is required only for brainwallet and incognito inputs
                       with non-standard (< {dsl}-bit) seed lengths.
                       with non-standard (< {dsl}-bit) seed lengths.
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{g.dfl_hash_preset}')
+                      for password hashing (default: '{gc.dfl_hash_preset}')
 -z, --show-hash-presets Show information on available hash presets
 -z, --show-hash-presets Show information on available hash presets
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -q, --quiet           Produce quieter output; suppress some warnings
 -q, --quiet           Produce quieter output; suppress some warnings
@@ -111,9 +111,10 @@ FMT CODES:
 			kgs=help_notes('keygen_backends'),
 			kgs=help_notes('keygen_backends'),
 			coin_id=help_notes('coin_id'),
 			coin_id=help_notes('coin_id'),
 			dsl=help_notes('dfl_seed_len'),
 			dsl=help_notes('dfl_seed_len'),
-			pnm=g.proj_name,
+			pnm=gc.proj_name,
 			what=gen_what,
 			what=gen_what,
 			g=g,
 			g=g,
+			gc=gc,
 		),
 		),
 		'notes': lambda help_notes,s: s.format(
 		'notes': lambda help_notes,s: s.format(
 			n_addrkey=note_addrkey,
 			n_addrkey=note_addrkey,

+ 5 - 5
mmgen/main_addrimport.py

@@ -23,7 +23,7 @@ mmgen-addrimport: Import addresses into a MMGen coin daemon tracking wallet
 from collections import namedtuple
 from collections import namedtuple
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import gc
 from .opts import opt
 from .opts import opt
 from .util import msg,qmsg,suf,die,fmt,async_run
 from .util import msg,qmsg,suf,die,fmt,async_run
 from .addrlist import AddrList,KeyAddrList
 from .addrlist import AddrList,KeyAddrList
@@ -31,7 +31,7 @@ from .tw.shared import TwLabel
 
 
 opts_data = {
 opts_data = {
 	'text': {
 	'text': {
-		'desc': f'Import addresses into an {g.proj_name} tracking wallet',
+		'desc': f'Import addresses into an {gc.proj_name} tracking wallet',
 		'usage':'[opts] [MMGen address file]',
 		'usage':'[opts] [MMGen address file]',
 		'options': """
 		'options': """
 -h, --help         Print this help message
 -h, --help         Print this help message
@@ -78,8 +78,8 @@ addrimport_msgs = {
 		by the number of addresses imported and typically takes just a few minutes.
 		by the number of addresses imported and typically takes just a few minutes.
 	""",
 	""",
 	'bad_args': f"""
 	'bad_args': f"""
-		You must specify either an {g.proj_name} address file, a single address with
-		the ‘--address’ option, or a flat list of non-{g.proj_name} addresses with
+		You must specify either an {gc.proj_name} address file, a single address with
+		the ‘--address’ option, or a flat list of non-{gc.proj_name} addresses with
 		the ‘--addrlist’ option.
 		the ‘--addrlist’ option.
 	"""
 	"""
 }
 }
@@ -102,7 +102,7 @@ def parse_cmd_args(rpc,cmd_args):
 				proto = proto,
 				proto = proto,
 				addrlist = get_lines_from_file(
 				addrlist = get_lines_from_file(
 					infile,
 					infile,
-					f'non-{g.proj_name} addresses',
+					f'non-{gc.proj_name} addresses',
 					trim_comments = True ) )
 					trim_comments = True ) )
 		else:
 		else:
 			al = import_mmgen_list(infile)
 			al = import_mmgen_list(infile)

+ 11 - 9
mmgen/main_passgen.py

@@ -22,7 +22,7 @@ mmgen-passgen: Generate a series or range of passwords from an MMGen
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .addrlist import AddrIdxList
 from .addrlist import AddrIdxList
 from .passwdlist import PasswordList
 from .passwdlist import PasswordList
@@ -35,7 +35,7 @@ opts_data = {
 	'sets': [('print_checksum',True,'quiet',True)],
 	'sets': [('print_checksum',True,'quiet',True)],
 	'text': {
 	'text': {
 		'desc': f"""
 		'desc': f"""
-                 Generate a range or list of passwords from an {g.proj_name} wallet,
+                 Generate a range or list of passwords from an {gc.proj_name} wallet,
                  mnemonic, seed or brainwallet for the given ID string
                  mnemonic, seed or brainwallet for the given ID string
 		 """,
 		 """,
 		'usage':'[opts] [seed source] <ID string> <index list or range(s)>',
 		'usage':'[opts] [seed source] <ID string> <index list or range(s)>',
@@ -57,7 +57,7 @@ opts_data = {
                       is required only for brainwallet and incognito inputs
                       is required only for brainwallet and incognito inputs
                       with non-standard (< {dsl}-bit) seed lengths.
                       with non-standard (< {dsl}-bit) seed lengths.
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{g.dfl_hash_preset}')
+                      for password hashing (default: '{gc.dfl_hash_preset}')
 -z, --show-hash-presets Show information on available hash presets
 -z, --show-hash-presets Show information on available hash presets
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -q, --quiet           Produce quieter output; suppress some warnings
 -q, --quiet           Produce quieter output; suppress some warnings
@@ -86,17 +86,17 @@ PASSWORD FORMATS:
 EXAMPLES:
 EXAMPLES:
 
 
   Generate ten base58 passwords of length {i58.dfl_len} for Alice's email account:
   Generate ten base58 passwords of length {i58.dfl_len} for Alice's email account:
-  {g.prog_name} alice@nowhere.com 1-10
+  {gc.prog_name} alice@nowhere.com 1-10
 
 
   Generate ten base58 passwords of length 16 for Alice's email account:
   Generate ten base58 passwords of length 16 for Alice's email account:
-  {g.prog_name} --passwd-len=16 alice@nowhere.com 1-10
+  {gc.prog_name} --passwd-len=16 alice@nowhere.com 1-10
 
 
   Generate ten base32 passwords of length {i32.dfl_len} for Alice's email account:
   Generate ten base32 passwords of length {i32.dfl_len} for Alice's email account:
-  {g.prog_name} --passwd-fmt=b32 alice@nowhere.com 1-10
+  {gc.prog_name} --passwd-fmt=b32 alice@nowhere.com 1-10
 
 
   Generate three BIP39 mnemonic seed phrases of length {i39.dfl_len} for Alice's
   Generate three BIP39 mnemonic seed phrases of length {i39.dfl_len} for Alice's
   Trezor device:
   Trezor device:
-  {g.prog_name} --passwd-fmt=bip39 mytrezor 1-3
+  {gc.prog_name} --passwd-fmt=bip39 mytrezor 1-3
 
 
   All passwords are cryptographically unlinkable with each other, including
   All passwords are cryptographically unlinkable with each other, including
   passwords with the same format but different length, so Alice needn't worry
   passwords with the same format but different length, so Alice needn't worry
@@ -116,9 +116,10 @@ FMT CODES:
 	},
 	},
 	'code': {
 	'code': {
 		'options': lambda help_notes,s: s.format(
 		'options': lambda help_notes,s: s.format(
-			g=g,pnm=g.proj_name,
+			g=g,pnm=gc.proj_name,
 			dsl=help_notes('dfl_seed_len'),
 			dsl=help_notes('dfl_seed_len'),
 			dpf=PasswordList.dfl_pw_fmt,
 			dpf=PasswordList.dfl_pw_fmt,
+			gc=gc,
 		),
 		),
 		'notes': lambda help_notes,s: s.format(
 		'notes': lambda help_notes,s: s.format(
 				o=opts,g=g,i58=pwi['b58'],i32=pwi['b32'],i39=pwi['bip39'],
 				o=opts,g=g,i58=pwi['b58'],i32=pwi['b32'],i39=pwi['bip39'],
@@ -128,6 +129,7 @@ FMT CODES:
 				n_bw=help_notes('brainwallet'),
 				n_bw=help_notes('brainwallet'),
 				pfi=help_notes('password_formats'),
 				pfi=help_notes('password_formats'),
 				n_fmt=help_notes('fmt_codes'),
 				n_fmt=help_notes('fmt_codes'),
+				gc=gc,
 		)
 		)
 	}
 	}
 }
 }
@@ -178,7 +180,7 @@ if keypress_confirm('Encrypt password list?'):
 	af.encrypt()
 	af.encrypt()
 	af.write(binary=True,desc='encrypted password list')
 	af.write(binary=True,desc='encrypted password list')
 else:
 else:
-	if g.test_suite_popen_spawn and g.platform == 'win':
+	if g.test_suite_popen_spawn and gc.platform == 'win':
 		import time
 		import time
 		time.sleep(0.1)
 		time.sleep(0.1)
 	af.write(desc='password list')
 	af.write(desc='password list')

+ 2 - 2
mmgen/main_regtest.py

@@ -22,13 +22,13 @@ mmgen-regtest: Coin daemon regression test mode setup and operations for the MMG
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .util import die,async_run
 from .util import die,async_run
 
 
 opts_data = {
 opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
-		'desc': f'Coin daemon regression test mode setup and operations for the {g.proj_name} suite',
+		'desc': f'Coin daemon regression test mode setup and operations for the {gc.proj_name} suite',
 		'usage':   '[opts] <command>',
 		'usage':   '[opts] <command>',
 		'options': """
 		'options': """
 -h, --help          Print this help message
 -h, --help          Print this help message

+ 3 - 2
mmgen/main_seedjoin.py

@@ -22,7 +22,7 @@ mmgen-seedjoin: Regenerate an MMGen deterministic wallet from seed shares
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import msg,msg_r,qmsg,die
 from .util import msg,msg_r,qmsg,die
 from .color import yellow
 from .color import yellow
@@ -53,7 +53,7 @@ opts_data = {
 -L, --label=       l  Specify a label 'l' for output wallet
 -L, --label=       l  Specify a label 'l' for output wallet
 -M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
 -M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{g.dfl_hash_preset}')
+                      for password hashing (default: '{gc.dfl_hash_preset}')
 -z, --show-hash-presets Show information on available hash presets
 -z, --show-hash-presets Show information on available hash presets
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -q, --quiet           Produce quieter output; suppress some warnings
 -q, --quiet           Produce quieter output; suppress some warnings
@@ -86,6 +86,7 @@ FMT CODES:
 			ms_min=MasterShareIdx.min_val,
 			ms_min=MasterShareIdx.min_val,
 			ms_max=MasterShareIdx.max_val,
 			ms_max=MasterShareIdx.max_val,
 			g=g,
 			g=g,
+			gc=gc,
 		),
 		),
 		'notes': lambda help_notes,s: s.format(
 		'notes': lambda help_notes,s: s.format(
 			f=help_notes('fmt_codes'),
 			f=help_notes('fmt_codes'),

+ 3 - 3
mmgen/main_split.py

@@ -30,7 +30,7 @@ from .common import *
 opts_data = {
 opts_data = {
 	'text': {
 	'text': {
 		'desc': f"""
 		'desc': f"""
-               Split funds in an {g.proj_name} wallet after a chain fork using a
+               Split funds in an {gc.proj_name} wallet after a chain fork using a
                timelocked transaction
                timelocked transaction
 		 """,
 		 """,
 		'usage':'[opts] [output addr1] [output addr2]',
 		'usage':'[opts] [output addr1] [output addr2]',
@@ -54,7 +54,7 @@ opts_data = {
 	'notes': f"""\n
 	'notes': f"""\n
 This command creates two transactions: one (with the timelock) to be broadcast
 This command creates two transactions: one (with the timelock) to be broadcast
 on the long chain and one on the short chain after a replayable chain fork.
 on the long chain and one on the short chain after a replayable chain fork.
-Only {g.proj_name} addresses may be spent to.
+Only {gc.proj_name} addresses may be spent to.
 
 
 The command must be run on the longest chain.  The user is reponsible for
 The command must be run on the longest chain.  The user is reponsible for
 ensuring that the current chain is the longest.  The other chain is specified
 ensuring that the current chain is the longest.  The other chain is specified
@@ -99,7 +99,7 @@ if opt.other_coin.lower() not in [e[2] for e in proto.forks if e[3] == True]:
 	die(1,f'{opt.other_coin!r}: not a replayable fork of {proto.coin} chain')
 	die(1,f'{opt.other_coin!r}: not a replayable fork of {proto.coin} chain')
 
 
 if len(cmd_args) != 2:
 if len(cmd_args) != 2:
-	die(1,f'This command requires exactly two {g.proj_name} addresses as arguments')
+	die(1,f'This command requires exactly two {gc.proj_name} addresses as arguments')
 
 
 from .addr import MMGenID
 from .addr import MMGenID
 try:
 try:

+ 7 - 7
mmgen/main_tool.py

@@ -23,13 +23,13 @@ mmgen-tool:  Perform various MMGen- and cryptocoin-related operations.
 
 
 import sys,os,importlib
 import sys,os,importlib
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import msg,Msg,die,capfirst,suf,async_run
 from .util import msg,Msg,die,capfirst,suf,async_run
 
 
 opts_data = {
 opts_data = {
 	'text': {
 	'text': {
-		'desc':    f'Perform various {g.proj_name}- and cryptocoin-related operations',
+		'desc':    f'Perform various {gc.proj_name}- and cryptocoin-related operations',
 		'usage':   '[opts] <command> <command args>',
 		'usage':   '[opts] <command> <command args>',
 		'options': """
 		'options': """
 -d, --outdir=       d  Specify an alternate directory 'd' for output
 -d, --outdir=       d  Specify an alternate directory 'd' for output
@@ -41,7 +41,7 @@ opts_data = {
                        for {coin_id}: {kgs}
                        for {coin_id}: {kgs}
 -l, --list             List available commands
 -l, --list             List available commands
 -p, --hash-preset= p   Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p   Use the scrypt hash parameters defined by preset 'p'
-                       for password hashing (default: '{g.dfl_hash_preset}')
+                       for password hashing (default: '{gc.dfl_hash_preset}')
 -P, --passwd-file= f   Get passphrase from file 'f'.
 -P, --passwd-file= f   Get passphrase from file 'f'.
 -q, --quiet            Produce quieter output
 -q, --quiet            Produce quieter output
 -r, --usr-randchars=n  Get 'n' characters of additional randomness from
 -r, --usr-randchars=n  Get 'n' characters of additional randomness from
@@ -65,10 +65,11 @@ Type ‘{pn} help <command>’ for help on a particular command
 			kgs=help_notes('keygen_backends'),
 			kgs=help_notes('keygen_backends'),
 			coin_id=help_notes('coin_id'),
 			coin_id=help_notes('coin_id'),
 			g=g,
 			g=g,
+			gc=gc,
 		),
 		),
 		'notes': lambda s, help_notes: s.format(
 		'notes': lambda s, help_notes: s.format(
 			ch=help_notes('tool_help'),
 			ch=help_notes('tool_help'),
-			pn=g.prog_name)
+			pn=gc.prog_name)
 	}
 	}
 }
 }
 
 
@@ -269,8 +270,7 @@ def process_args(cmd,cmd_args,cls):
 			die(1,"'Binary input data must be supplied via STDIN")
 			die(1,"'Binary input data must be supplied via STDIN")
 
 
 		if have_stdin_input and arg_type == 'str' and isinstance(arg,bytes):
 		if have_stdin_input and arg_type == 'str' and isinstance(arg,bytes):
-			from .globalvars import g
-			NL = '\r\n' if g.platform == 'win' else '\n'
+			NL = '\r\n' if gc.platform == 'win' else '\n'
 			arg = arg.decode()
 			arg = arg.decode()
 			if arg[-len(NL):] == NL: # rstrip one newline
 			if arg[-len(NL):] == NL: # rstrip one newline
 				arg = arg[:-len(NL)]
 				arg = arg[:-len(NL)]
@@ -346,7 +346,7 @@ def get_cmd_cls(cmd):
 def get_mod_cls(modname):
 def get_mod_cls(modname):
 	return getattr(importlib.import_module(f'mmgen.tool.{modname}'),'tool_cmd')
 	return getattr(importlib.import_module(f'mmgen.tool.{modname}'),'tool_cmd')
 
 
-if g.prog_name == 'mmgen-tool' and not opt._lock:
+if gc.prog_name == 'mmgen-tool' and not opt._lock:
 
 
 	po = opts.init( opts_data, parse_only=True )
 	po = opts.init( opts_data, parse_only=True )
 
 

+ 7 - 7
mmgen/main_txbump.py

@@ -22,7 +22,7 @@ mmgen-txbump: Increase the fee on a replaceable (replace-by-fee) MMGen
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import gc
 from .opts import opt
 from .opts import opt
 from .util import msg,msg_r,qmsg,die,async_run
 from .util import msg,msg_r,qmsg,die,async_run
 from .color import green
 from .color import green
@@ -32,11 +32,11 @@ opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
 		'desc': f"""
 		'desc': f"""
-                Increase the fee on a replaceable (RBF) {g.proj_name} transaction,
+                Increase the fee on a replaceable (RBF) {gc.proj_name} transaction,
                 creating a new transaction, and optionally sign and send the
                 creating a new transaction, and optionally sign and send the
                 new transaction
                 new transaction
 		 """,
 		 """,
-		'usage':   f'[opts] <{g.proj_name} TX file> [seed source] ...',
+		'usage':   f'[opts] <{gc.proj_name} TX file> [seed source] ...',
 		'options': """
 		'options': """
 -h, --help             Print this help message
 -h, --help             Print this help message
 --, --longhelp         Print help message for long options (common options)
 --, --longhelp         Print help message for long options (common options)
@@ -66,7 +66,7 @@ opts_data = {
                        for the transaction's change output, if present)
                        for the transaction's change output, if present)
 -O, --old-incog-fmt    Specify old-format incognito input
 -O, --old-incog-fmt    Specify old-format incognito input
 -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
-                       for password hashing (default: '{g.dfl_hash_preset}')
+                       for password hashing (default: '{gc.dfl_hash_preset}')
 -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
 -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
 -q, --quiet            Suppress warnings; overwrite files without prompting
 -q, --quiet            Suppress warnings; overwrite files without prompting
 -s, --send             Sign and send the transaction (the default if seed
 -s, --send             Sign and send the transaction (the default if seed
@@ -87,9 +87,9 @@ FMT CODES:
 	},
 	},
 	'code': {
 	'code': {
 		'options': lambda help_notes,proto,s: s.format(
 		'options': lambda help_notes,proto,s: s.format(
-			g=g,
-			pnm=g.proj_name,
-			pnl=g.proj_name.lower(),
+			gc=gc,
+			pnm=gc.proj_name,
+			pnl=gc.proj_name.lower(),
 			fu=help_notes('rel_fee_desc'),
 			fu=help_notes('rel_fee_desc'),
 			fl=help_notes('fee_spec_letters'),
 			fl=help_notes('fee_spec_letters'),
 			kgs=help_notes('keygen_backends'),
 			kgs=help_notes('keygen_backends'),

+ 2 - 2
mmgen/main_txcreate.py

@@ -22,14 +22,14 @@ mmgen-txcreate: Create a cryptocoin transaction with MMGen- and/or non-MMGen
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import fmt_list,async_run
 from .util import fmt_list,async_run
 
 
 opts_data = {
 opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
-		'desc': f'Create a transaction with outputs to specified coin or {g.proj_name} addresses',
+		'desc': f'Create a transaction with outputs to specified coin or {gc.proj_name} addresses',
 		'usage':   '[opts]  [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...]',
 		'usage':   '[opts]  [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...]',
 		'options': """
 		'options': """
 -h, --help            Print this help message
 -h, --help            Print this help message

+ 4 - 4
mmgen/main_txdo.py

@@ -21,7 +21,7 @@ mmgen-txdo: Create, sign and broadcast an online MMGen transaction
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import die,fmt_list,async_run
 from .util import die,fmt_list,async_run
 from .wallet import Wallet
 from .wallet import Wallet
@@ -30,7 +30,7 @@ from .subseed import SubSeedIdxRange
 opts_data = {
 opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
-		'desc': f'Create, sign and send an {g.proj_name} transaction',
+		'desc': f'Create, sign and send an {gc.proj_name} transaction',
 		'usage':   '[opts]  [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...] [seed source ...]',
 		'usage':   '[opts]  [<addr,amt> ...] <change addr, addrlist ID or addr type> [addr file ...] [seed source ...]',
 		'options': """
 		'options': """
 -h, --help             Print this help message
 -h, --help             Print this help message
@@ -75,7 +75,7 @@ opts_data = {
                        mappings, so the user should record its checksum.
                        mappings, so the user should record its checksum.
 -O, --old-incog-fmt    Specify old-format incognito input
 -O, --old-incog-fmt    Specify old-format incognito input
 -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
-                       for password hashing (default: '{g.dfl_hash_preset}')
+                       for password hashing (default: '{gc.dfl_hash_preset}')
 -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
 -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
 -r, --rbf              Make transaction BIP 125 (replace-by-fee) replaceable
 -r, --rbf              Make transaction BIP 125 (replace-by-fee) replaceable
 -q, --quiet            Suppress warnings; overwrite files without prompting
 -q, --quiet            Suppress warnings; overwrite files without prompting
@@ -104,7 +104,7 @@ FMT CODES:
 	},
 	},
 	'code': {
 	'code': {
 		'options': lambda proto,help_notes,s: s.format(
 		'options': lambda proto,help_notes,s: s.format(
-			g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),
+			g=g,gc=gc,pnm=gc.proj_name,pnl=gc.proj_name.lower(),
 			kgs=help_notes('keygen_backends'),
 			kgs=help_notes('keygen_backends'),
 			coin_id=help_notes('coin_id'),
 			coin_id=help_notes('coin_id'),
 			fu=help_notes('rel_fee_desc'),
 			fu=help_notes('rel_fee_desc'),

+ 2 - 2
mmgen/main_txsend.py

@@ -23,14 +23,14 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
 import sys
 import sys
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import gc
 from .opts import opt
 from .opts import opt
 from .util import vmsg,qmsg,async_run
 from .util import vmsg,qmsg,async_run
 
 
 opts_data = {
 opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
-		'desc':    f'Send a signed {g.proj_name} cryptocoin transaction',
+		'desc':    f'Send a signed {gc.proj_name} cryptocoin transaction',
 		'usage':   '[opts] <signed transaction file>',
 		'usage':   '[opts] <signed transaction file>',
 		'options': """
 		'options': """
 -h, --help      Print this help message
 -h, --help      Print this help message

+ 6 - 6
mmgen/main_txsign.py

@@ -21,7 +21,7 @@ mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate'
 """
 """
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import gc
 from .opts import opt
 from .opts import opt
 from .util import msg,ymsg,die,async_run
 from .util import msg,ymsg,die,async_run
 from .subseed import SubSeedIdxRange
 from .subseed import SubSeedIdxRange
@@ -32,7 +32,7 @@ from .color import orange
 opts_data = {
 opts_data = {
 	'sets': [('yes', True, 'quiet', True)],
 	'sets': [('yes', True, 'quiet', True)],
 	'text': {
 	'text': {
-		'desc':    f'Sign cryptocoin transactions generated by {g.proj_name.lower()}-txcreate',
+		'desc':    f'Sign cryptocoin transactions generated by {gc.proj_name.lower()}-txcreate',
 		'usage':   '[opts] <transaction file>... [seed source]...',
 		'usage':   '[opts] <transaction file>... [seed source]...',
 		'options': """
 		'options': """
 -h, --help            Print this help message
 -h, --help            Print this help message
@@ -51,7 +51,7 @@ opts_data = {
                       is required only for brainwallet and incognito inputs
                       is required only for brainwallet and incognito inputs
                       with non-standard (< {dsl}-bit) seed lengths.
                       with non-standard (< {dsl}-bit) seed lengths.
 -p, --hash-preset=p   Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset=p   Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{g.dfl_hash_preset}')
+                      for password hashing (default: '{gc.dfl_hash_preset}')
 -z, --show-hash-presets Show information on available hash presets
 -z, --show-hash-presets Show information on available hash presets
 -k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
 -k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
 -K, --keygen-backend=n Use backend 'n' for public key generation.  Options
 -K, --keygen-backend=n Use backend 'n' for public key generation.  Options
@@ -84,9 +84,9 @@ FMT CODES:
 	},
 	},
 	'code': {
 	'code': {
 		'options': lambda proto,help_notes,s: s.format(
 		'options': lambda proto,help_notes,s: s.format(
-			g=g,
-			pnm=g.proj_name,
-			pnl=g.proj_name.lower(),
+			gc=gc,
+			pnm=gc.proj_name,
+			pnl=gc.proj_name.lower(),
 			kgs=help_notes('keygen_backends'),
 			kgs=help_notes('keygen_backends'),
 			coin_id=help_notes('coin_id'),
 			coin_id=help_notes('coin_id'),
 			dsl=help_notes('dfl_seed_len'),
 			dsl=help_notes('dfl_seed_len'),

+ 6 - 5
mmgen/main_wallet.py

@@ -22,7 +22,7 @@ main_wallet: Entry point for MMGen wallet-related scripts
 
 
 import sys,os
 import sys,os
 import mmgen.opts as opts
 import mmgen.opts as opts
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .color import green,yellow
 from .color import green,yellow
 from .util import msg,qmsg,vmsg,gmsg_r,ymsg,bmsg,die,capfirst
 from .util import msg,qmsg,vmsg,gmsg_r,ymsg,bmsg,die,capfirst
@@ -43,13 +43,13 @@ invoked_as = {
 	'mmgen-passchg':      'passchg',
 	'mmgen-passchg':      'passchg',
 	'mmgen-subwalletgen': 'subgen',
 	'mmgen-subwalletgen': 'subgen',
 	'mmgen-seedsplit':    'seedsplit',
 	'mmgen-seedsplit':    'seedsplit',
-}[g.prog_name]
+}[gc.prog_name]
 
 
-dsw = f'the default or specified {g.proj_name} wallet'
+dsw = f'the default or specified {gc.proj_name} wallet'
 
 
 # full: defhHiJkKlLmoOpPqrSvz-
 # full: defhHiJkKlLmoOpPqrSvz-
 if invoked_as == 'gen':
 if invoked_as == 'gen':
-	desc = f'Generate an {g.proj_name} wallet from a random seed'
+	desc = f'Generate an {gc.proj_name} wallet from a random seed'
 	opt_filter = 'ehdoJlLpPqrSvz-'
 	opt_filter = 'ehdoJlLpPqrSvz-'
 	usage = '[opts]'
 	usage = '[opts]'
 	oaction = 'output'
 	oaction = 'output'
@@ -108,7 +108,7 @@ opts_data = {
 -m, --keep-label      Reuse label of input wallet for output wallet
 -m, --keep-label      Reuse label of input wallet for output wallet
 -M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
 -M, --master-share=i  Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
 -p, --hash-preset= p  Use the scrypt hash parameters defined by preset 'p'
-                      for password hashing (default: '{g.dfl_hash_preset}')
+                      for password hashing (default: '{gc.dfl_hash_preset}')
 -z, --show-hash-presets Show information on available hash presets
 -z, --show-hash-presets Show information on available hash presets
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -P, --passwd-file= f  Get wallet passphrase from file 'f'
 -q, --quiet           Produce quieter output; suppress some warnings
 -q, --quiet           Produce quieter output; suppress some warnings
@@ -134,6 +134,7 @@ FMT CODES:
 			ms_max=help_notes('MasterShareIdx').max_val,
 			ms_max=help_notes('MasterShareIdx').max_val,
 			dsl=help_notes('dfl_seed_len'),
 			dsl=help_notes('dfl_seed_len'),
 			g=g,
 			g=g,
+			gc=gc,
 		),
 		),
 		'notes': lambda help_notes,s: s.format(
 		'notes': lambda help_notes,s: s.format(
 			f=help_notes('fmt_codes'),
 			f=help_notes('fmt_codes'),

+ 2 - 1
mmgen/main_xmrwallet.py

@@ -51,7 +51,7 @@ opts_data = {
                                  {R}
                                  {R}
 -k, --use-internal-keccak-module Force use of the internal keccak module
 -k, --use-internal-keccak-module Force use of the internal keccak module
 -p, --hash-preset=P              Use scrypt hash preset 'P' for password
 -p, --hash-preset=P              Use scrypt hash preset 'P' for password
-                                 hashing (default: '{g.dfl_hash_preset}')
+                                 hashing (default: '{gc.dfl_hash_preset}')
 -r, --restore-height=H           Scan from height 'H' when creating wallets
 -r, --restore-height=H           Scan from height 'H' when creating wallets
 -R, --no-relay                   Save transaction to file instead of relaying
 -R, --no-relay                   Save transaction to file instead of relaying
 -s, --no-start-wallet-daemon     Don’t start the wallet daemon at startup
 -s, --no-start-wallet-daemon     Don’t start the wallet daemon at startup
@@ -216,6 +216,7 @@ $ mmgen-xmrwallet --pager txview *XMR*.sigtx
 			D=xmrwallet_uarg_info['daemon'].annot,
 			D=xmrwallet_uarg_info['daemon'].annot,
 			R=xmrwallet_uarg_info['tx_relay_daemon'].annot,
 			R=xmrwallet_uarg_info['tx_relay_daemon'].annot,
 			g=g,
 			g=g,
+			gc=gc,
 		),
 		),
 	}
 	}
 }
 }

+ 2 - 2
mmgen/msg.py

@@ -13,7 +13,7 @@ msg: base message signing classes
 """
 """
 
 
 import os,importlib,json
 import os,importlib,json
-from .globalvars import g
+from .globalvars import gc
 from .objmethods import MMGenObject,Hilite,InitErrors
 from .objmethods import MMGenObject,Hilite,InitErrors
 from .util import msg,die,suf,make_chksum_6,fmt_list,remove_dups
 from .util import msg,die,suf,make_chksum_6,fmt_list,remove_dups
 from .color import red,orange,grnbg
 from .color import red,orange,grnbg
@@ -92,7 +92,7 @@ class coin_msg:
 
 
 		def write_to_file(self,outdir=None,ask_overwrite=False):
 		def write_to_file(self,outdir=None,ask_overwrite=False):
 			data = {
 			data = {
-				'id': f'{g.proj_name} {self.desc}',
+				'id': f'{gc.proj_name} {self.desc}',
 				'metadata': self.data,
 				'metadata': self.data,
 				'signatures': self.sigs,
 				'signatures': self.sigs,
 			}
 			}

+ 10 - 10
mmgen/opts.py

@@ -21,7 +21,7 @@ opts: MMGen-specific options processing after generic processing by share.Opts
 """
 """
 import sys,os
 import sys,os
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .base_obj import Lockable
 from .base_obj import Lockable
 
 
 import mmgen.share.Opts
 import mmgen.share.Opts
@@ -36,14 +36,14 @@ opt = UserOpts()
 
 
 def usage():
 def usage():
 	from .util import Die
 	from .util import Die
-	Die(1,mmgen.share.Opts.make_usage_str(g.prog_name,'user',usage_data))
+	Die(1,mmgen.share.Opts.make_usage_str(gc.prog_name,'user',usage_data))
 
 
 def version():
 def version():
 	from .util import Die,fmt
 	from .util import Die,fmt
 	Die(0,fmt(f"""
 	Die(0,fmt(f"""
-		{g.prog_name.upper()} version {g.version}
-		Part of the {g.proj_name} suite, an online/offline cryptocurrency wallet for the
-		command line.  Copyright (C){g.Cdates} {g.author} {g.email}
+		{gc.prog_name.upper()} version {gc.version}
+		Part of the {gc.proj_name} suite, an online/offline cryptocurrency wallet for the
+		command line.  Copyright (C){gc.Cdates} {gc.author} {gc.email}
 	""",indent='  ').rstrip())
 	""",indent='  ').rstrip())
 
 
 def delete_data(opts_data):
 def delete_data(opts_data):
@@ -167,7 +167,7 @@ def override_globals_from_cfg_file(
 	for d in ucfg.get_lines():
 	for d in ucfg.get_lines():
 		if d.name in g.cfg_file_opts:
 		if d.name in g.cfg_file_opts:
 			ns = d.name.split('_')
 			ns = d.name.split('_')
-			if ns[0] in g.core_coins:
+			if ns[0] in gc.core_coins:
 				if not need_proto:
 				if not need_proto:
 					continue
 					continue
 				nse,tn = (
 				nse,tn = (
@@ -267,7 +267,7 @@ common_opts_data = {
 --, --carol                Specify user “Carol” in MMGen regtest mode
 --, --carol                Specify user “Carol” in MMGen regtest mode
 	""",
 	""",
 	'code': lambda help_notes,proto,s: s.format(
 	'code': lambda help_notes,proto,s: s.format(
-			pnm    = g.proj_name,
+			pnm    = gc.proj_name,
 			cu_dfl = proto.coin,
 			cu_dfl = proto.coin,
 		)
 		)
 }
 }
@@ -369,7 +369,7 @@ def init(
 			if val != None and hasattr(g,k):
 			if val != None and hasattr(g,k):
 				setattr(g,k,set_for_type(val,getattr(g,k),'--'+k))
 				setattr(g,k,set_for_type(val,getattr(g,k),'--'+k))
 
 
-	if g.regtest or g.bob or g.alice or g.carol or g.prog_name == 'mmgen-regtest':
+	if g.regtest or g.bob or g.alice or g.carol or gc.prog_name == 'mmgen-regtest':
 		g.network = 'regtest'
 		g.network = 'regtest'
 		g.regtest_user = 'bob' if g.bob else 'alice' if g.alice else 'carol' if g.carol else None
 		g.regtest_user = 'bob' if g.bob else 'alice' if g.alice else 'carol' if g.carol else None
 	else:
 	else:
@@ -422,7 +422,7 @@ def init(
 	if opt.verbose:
 	if opt.verbose:
 		opt.quiet = None
 		opt.quiet = None
 
 
-	if g.debug and g.prog_name != 'test.py':
+	if g.debug and gc.prog_name != 'test.py':
 		opt.verbose,opt.quiet = (True,None)
 		opt.verbose,opt.quiet = (True,None)
 
 
 	if g.debug_opts:
 	if g.debug_opts:
@@ -609,7 +609,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
 #		except:
 #		except:
 #			die( 'UserOptError',
 #			die( 'UserOptError',
 #				'Regtest (Bob and Alice) mode not set up yet.  ' +
 #				'Regtest (Bob and Alice) mode not set up yet.  ' +
-#				f"Run '{g.proj_name.lower()}-regtest setup' to initialize." )
+#				f"Run '{gc.proj_name.lower()}-regtest setup' to initialize." )
 #
 #
 #	chk_alice = chk_bob
 #	chk_alice = chk_bob
 
 

+ 4 - 4
mmgen/proto/btc/daemon.py

@@ -14,7 +14,7 @@ proto.btc.daemon: Bitcoin base protocol daemon classes
 
 
 import os
 import os
 
 
-from ...globalvars import g
+from ...globalvars import g,gc
 from ...opts import opt
 from ...opts import opt
 from ...util import list_gen
 from ...util import list_gen
 from ...daemon import CoinDaemon,_nw,_dd
 from ...daemon import CoinDaemon,_nw,_dd
@@ -29,7 +29,7 @@ class bitcoin_core_daemon(CoinDaemon):
 	rpc_ports = _nw(8332, 18332, 18443)
 	rpc_ports = _nw(8332, 18332, 18443)
 	cfg_file = 'bitcoin.conf'
 	cfg_file = 'bitcoin.conf'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.bitcoin'],
+		'linux': [gc.home_dir,'.bitcoin'],
 		'win':   [os.getenv('APPDATA'),'Bitcoin']
 		'win':   [os.getenv('APPDATA'),'Bitcoin']
 	}
 	}
 	nonstd_datadir = False
 	nonstd_datadir = False
@@ -133,7 +133,7 @@ class bitcoin_cash_node_daemon(bitcoin_core_daemon):
 	cfg_file_hdr = '# Bitcoin Cash Node config file\n'
 	cfg_file_hdr = '# Bitcoin Cash Node config file\n'
 	nonstd_datadir = True
 	nonstd_datadir = True
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.bitcoin-bchn'],
+		'linux': [gc.home_dir,'.bitcoin-bchn'],
 		'win':   [os.getenv('APPDATA'),'Bitcoin_ABC']
 		'win':   [os.getenv('APPDATA'),'Bitcoin_ABC']
 	}
 	}
 
 
@@ -162,6 +162,6 @@ class litecoin_core_daemon(bitcoin_core_daemon):
 	cfg_file = 'litecoin.conf'
 	cfg_file = 'litecoin.conf'
 	cfg_file_hdr = '# Litecoin Core config file\n'
 	cfg_file_hdr = '# Litecoin Core config file\n'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.litecoin'],
+		'linux': [gc.home_dir,'.litecoin'],
 		'win':   [os.getenv('APPDATA'),'Litecoin']
 		'win':   [os.getenv('APPDATA'),'Litecoin']
 	}
 	}

+ 4 - 4
mmgen/proto/eth/daemon.py

@@ -14,7 +14,7 @@ proto.eth.daemon: Ethereum base protocol daemon classes
 
 
 import os
 import os
 
 
-from ...globalvars import g
+from ...globalvars import gc
 from ...util import list_gen,get_subclasses
 from ...util import list_gen,get_subclasses
 from ...daemon import CoinDaemon,RPCDaemon,_nw,_dd
 from ...daemon import CoinDaemon,RPCDaemon,_nw,_dd
 
 
@@ -60,7 +60,7 @@ class openethereum_daemon(ethereum_daemon):
 	exec_fn = 'openethereum'
 	exec_fn = 'openethereum'
 	cfg_file = 'parity.conf'
 	cfg_file = 'parity.conf'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.local','share','io.parity.ethereum'],
+		'linux': [gc.home_dir,'.local','share','io.parity.ethereum'],
 		'win':   [os.getenv('LOCALAPPDATA'),'Parity','Ethereum']
 		'win':   [os.getenv('LOCALAPPDATA'),'Parity','Ethereum']
 	}
 	}
 
 
@@ -97,7 +97,7 @@ class geth_daemon(ethereum_daemon):
 	avail_opts = ('no_daemonize','online')
 	avail_opts = ('no_daemonize','online')
 	version_info_arg = 'version'
 	version_info_arg = 'version'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.ethereum','geth'],
+		'linux': [gc.home_dir,'.ethereum','geth'],
 		'win':   [os.getenv('LOCALAPPDATA'),'Geth'] # FIXME
 		'win':   [os.getenv('LOCALAPPDATA'),'Geth'] # FIXME
 	}
 	}
 
 
@@ -133,7 +133,7 @@ class erigon_daemon(geth_daemon):
 	torrent_ports = _nw(42069,42070,None) # testnet is non-standard
 	torrent_ports = _nw(42069,42070,None) # testnet is non-standard
 	version_info_arg = '--version'
 	version_info_arg = '--version'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.local','share','erigon'],
+		'linux': [gc.home_dir,'.local','share','erigon'],
 		'win':   [os.getenv('LOCALAPPDATA'),'Erigon'] # FIXME
 		'win':   [os.getenv('LOCALAPPDATA'),'Erigon'] # FIXME
 	}
 	}
 
 

+ 2 - 2
mmgen/proto/xmr/daemon.py

@@ -14,7 +14,7 @@ proto.xmr.daemon: Monero base protocol daemon classes
 
 
 import os
 import os
 
 
-from ...globalvars import g
+from ...globalvars import g,gc
 from ...opts import opt
 from ...opts import opt
 from ...util import list_gen,die,contains_any
 from ...util import list_gen,die,contains_any
 from ...daemon import CoinDaemon,RPCDaemon,_nw,_dd
 from ...daemon import CoinDaemon,RPCDaemon,_nw,_dd
@@ -29,7 +29,7 @@ class monero_daemon(CoinDaemon):
 	rpc_ports = _nw(18081, 38081, None) # testnet is stagenet
 	rpc_ports = _nw(18081, 38081, None) # testnet is stagenet
 	cfg_file = 'bitmonero.conf'
 	cfg_file = 'bitmonero.conf'
 	datadirs = {
 	datadirs = {
-		'linux': [g.home_dir,'.bitmonero'],
+		'linux': [gc.home_dir,'.bitmonero'],
 		'win':   ['/','c','ProgramData','bitmonero']
 		'win':   ['/','c','ProgramData','bitmonero']
 	}
 	}
 
 

+ 6 - 6
mmgen/protocol.py

@@ -22,7 +22,7 @@ protocol: Coin protocol base classes and initializer
 
 
 from collections import namedtuple
 from collections import namedtuple
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .objmethods import MMGenObject
 from .objmethods import MMGenObject
 
 
 decoded_wif = namedtuple('decoded_wif',['sec','pubkey_type','compressed'])
 decoded_wif = namedtuple('decoded_wif',['sec','pubkey_type','compressed'])
@@ -36,7 +36,7 @@ class CoinProtocol(MMGenObject):
 
 
 	proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin.py
 	proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin.py
 
 
-	# keys are mirrored in g.core_coins:
+	# keys are mirrored in gc.core_coins:
 	coins = {
 	coins = {
 		'btc': proto_info('Bitcoin',         5),
 		'btc': proto_info('Bitcoin',         5),
 		'bch': proto_info('BitcoinCash',     5),
 		'bch': proto_info('BitcoinCash',     5),
@@ -81,9 +81,9 @@ class CoinProtocol(MMGenObject):
 				self.addr_fmt_to_ver_bytes = {v:k for k,v in self.addr_ver_bytes.items()}
 				self.addr_fmt_to_ver_bytes = {v:k for k,v in self.addr_ver_bytes.items()}
 				self.addr_ver_bytes_len = len(list(self.addr_ver_bytes)[0])
 				self.addr_ver_bytes_len = len(list(self.addr_ver_bytes)[0])
 
 
-			if 'tx' not in self.mmcaps and g.is_txprog:
+			if 'tx' not in self.mmcaps and gc.is_txprog:
 				from .util import die
 				from .util import die
-				die(2,f'Command {g.prog_name!r} not supported for coin {self.coin}')
+				die(2,f'Command {gc.prog_name!r} not supported for coin {self.coin}')
 
 
 			if hasattr(self,'chain_names'):
 			if hasattr(self,'chain_names'):
 				self.chain_name = self.chain_names[0] # first chain name is default
 				self.chain_name = self.chain_names[0] # first chain name is default
@@ -294,7 +294,7 @@ def warn_trustlevel(coinsym):
 		trust_level = e.trust_level if e else None
 		trust_level = e.trust_level if e else None
 		if trust_level in (None,-1):
 		if trust_level in (None,-1):
 			from .util import die
 			from .util import die
-			die(1,f'Coin {coinsym} is not supported by {g.proj_name}')
+			die(1,f'Coin {coinsym} is not supported by {gc.proj_name}')
 
 
 	if trust_level > 3:
 	if trust_level > 3:
 		return
 		return
@@ -317,7 +317,7 @@ def warn_trustlevel(coinsym):
 			2: yellow('MEDIUM'),
 			2: yellow('MEDIUM'),
 			3: green('OK'),
 			3: green('OK'),
 		}[trust_level],
 		}[trust_level],
-		p = g.proj_name )
+		p = gc.proj_name )
 
 
 	if g.test_suite:
 	if g.test_suite:
 		qmsg(warning)
 		qmsg(warning)

+ 2 - 2
mmgen/rpc.py

@@ -264,7 +264,7 @@ class RPCClient(MMGenObject):
 	def __init__(self,host,port,test_connection=True):
 	def __init__(self,host,port,test_connection=True):
 
 
 		# aiohttp workaround, and may speed up RPC performance overall on some systems:
 		# aiohttp workaround, and may speed up RPC performance overall on some systems:
-		if g.platform == 'win' and host == 'localhost':
+		if gc.platform == 'win' and host == 'localhost':
 			host = '127.0.0.1'
 			host = '127.0.0.1'
 
 
 		global dmsg_rpc,dmsg_rpc_backend
 		global dmsg_rpc,dmsg_rpc_backend
@@ -291,7 +291,7 @@ class RPCClient(MMGenObject):
 	def _get_backend(self,backend):
 	def _get_backend(self,backend):
 		backend_id = backend or opt.rpc_backend
 		backend_id = backend or opt.rpc_backend
 		if backend_id == 'auto':
 		if backend_id == 'auto':
-			return {'linux':RPCBackends.httplib,'win':RPCBackends.requests}[g.platform](self)
+			return {'linux':RPCBackends.httplib,'win':RPCBackends.requests}[gc.platform](self)
 		else:
 		else:
 			return getattr(RPCBackends,backend_id)(self)
 			return getattr(RPCBackends,backend_id)(self)
 
 

+ 4 - 2
mmgen/term.py

@@ -22,7 +22,9 @@ term: Terminal classes for the MMGen suite
 
 
 import sys,os,time
 import sys,os,time
 from collections import namedtuple
 from collections import namedtuple
-from .common import *
+
+from .globalvars import g,gc
+from .util import msg,msg_r,die
 
 
 try:
 try:
 	import tty,termios
 	import tty,termios
@@ -43,7 +45,7 @@ class MMGenTerm(object):
 
 
 	@classmethod
 	@classmethod
 	def register_cleanup(cls):
 	def register_cleanup(cls):
-		if g.platform == 'linux' and not hasattr(cls,'cleanup_registered'):
+		if gc.platform == 'linux' and not hasattr(cls,'cleanup_registered'):
 			import atexit
 			import atexit
 			atexit.register(
 			atexit.register(
 				lambda: termios.tcsetattr(
 				lambda: termios.tcsetattr(

+ 2 - 2
mmgen/tool/fileutil.py

@@ -23,6 +23,7 @@ tool.fileutil: File routines for the 'mmgen-tool' utility
 import os
 import os
 
 
 from .common import tool_cmd_base
 from .common import tool_cmd_base
+from ..globalvars import gc
 from ..util import msg,msg_r,qmsg,die,suf,make_full_path
 from ..util import msg,msg_r,qmsg,die,suf,make_full_path
 from ..crypto import Crypto
 from ..crypto import Crypto
 
 
@@ -36,11 +37,10 @@ class tool_cmd(tool_cmd_base):
 		"Use an Incog ID to find hidden incognito wallet data"
 		"Use an Incog ID to find hidden incognito wallet data"
 
 
 		from hashlib import sha256
 		from hashlib import sha256
-		from ..globalvars import g
 
 
 		ivsize,bsize,mod = ( Crypto.aesctr_iv_len, 4096, 4096*8 )
 		ivsize,bsize,mod = ( Crypto.aesctr_iv_len, 4096, 4096*8 )
 		n,carry = 0,b' '*ivsize
 		n,carry = 0,b' '*ivsize
-		flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY
+		flgs = os.O_RDONLY|os.O_BINARY if gc.platform == 'win' else os.O_RDONLY
 		f = os.open(filename,flgs)
 		f = os.open(filename,flgs)
 		for ch in incog_id:
 		for ch in incog_id:
 			if ch not in '0123456789ABCDEF':
 			if ch not in '0123456789ABCDEF':

+ 2 - 2
mmgen/tool/help.py

@@ -133,7 +133,7 @@ def gen_tool_usage():
 
 
 def gen_tool_cmd_usage(mod,cmdname):
 def gen_tool_cmd_usage(mod,cmdname):
 
 
-	from ..globalvars import g
+	from ..globalvars import gc
 	from ..util import capfirst
 	from ..util import capfirst
 
 
 	cls = main_tool.get_mod_cls(mod)
 	cls = main_tool.get_mod_cls(mod)
@@ -145,7 +145,7 @@ def gen_tool_cmd_usage(mod,cmdname):
 	yield capfirst( docstr.split('\n')[0].strip() )
 	yield capfirst( docstr.split('\n')[0].strip() )
 	yield ''
 	yield ''
 	yield 'USAGE: {b} [OPTS] {c}{d}{e}'.format(
 	yield 'USAGE: {b} [OPTS] {c}{d}{e}'.format(
-		b = g.prog_name,
+		b = gc.prog_name,
 		c = cmdname,
 		c = cmdname,
 		d = f' {ARGS}' if ARGS else '',
 		d = f' {ARGS}' if ARGS else '',
 		e = f' [{KWARGS}]' if KWARGS else '' )
 		e = f' [{KWARGS}]' if KWARGS else '' )

+ 2 - 2
mmgen/tool/util.py

@@ -20,6 +20,7 @@
 tool.util: Utility commands for the 'mmgen-tool' utility
 tool.util: Utility commands for the 'mmgen-tool' utility
 """
 """
 
 
+from ..globalvars import gc
 from .common import tool_cmd_base
 from .common import tool_cmd_base
 
 
 class tool_cmd(tool_cmd_base):
 class tool_cmd(tool_cmd_base):
@@ -121,8 +122,7 @@ class tool_cmd(tool_cmd_base):
 
 
 	def unhexdump(self,infile:str):
 	def unhexdump(self,infile:str):
 		"decode hexdump from file (use '-' for stdin) (warning: outputs binary data)"
 		"decode hexdump from file (use '-' for stdin) (warning: outputs binary data)"
-		from ..globalvars import g
-		if g.platform == 'win':
+		if gc.platform == 'win':
 			import sys,os,msvcrt
 			import sys,os,msvcrt
 			msvcrt.setmode( sys.stdout.fileno(), os.O_BINARY )
 			msvcrt.setmode( sys.stdout.fileno(), os.O_BINARY )
 		from ..fileutil import get_data_from_file
 		from ..fileutil import get_data_from_file

+ 2 - 1
mmgen/tw/unspent.py

@@ -81,7 +81,8 @@ class TwUnspentOutputs(TwView):
 		await super().__init__(proto)
 		await super().__init__(proto)
 		self.minconf  = minconf
 		self.minconf  = minconf
 		self.addrs    = addrs
 		self.addrs    = addrs
-		self.min_cols = g.min_screen_width
+		from ..globalvars import gc
+		self.min_cols = gc.min_screen_width
 
 
 	@property
 	@property
 	def total(self):
 	def total(self):

+ 2 - 1
mmgen/tw/view.py

@@ -516,7 +516,8 @@ class TwView(MMGenObject,metaclass=AsyncInit):
 				for k in self.scroll_keys['vi']:
 				for k in self.scroll_keys['vi']:
 					assert k not in self.key_mappings, f'{k!r} is in key_mappings'
 					assert k not in self.key_mappings, f'{k!r} is in key_mappings'
 				self.key_mappings.update(self.scroll_keys['vi'])
 				self.key_mappings.update(self.scroll_keys['vi'])
-				self.key_mappings.update(self.scroll_keys[g.platform])
+				from ..globalvars import gc
+				self.key_mappings.update(self.scroll_keys[gc.platform])
 			return self.key_mappings
 			return self.key_mappings
 
 
 		scroll = self.scroll = g.scroll
 		scroll = self.scroll = g.scroll

+ 3 - 3
mmgen/tx/base.py

@@ -12,7 +12,7 @@
 tx.base: base transaction class
 tx.base: base transaction class
 """
 """
 
 
-from ..globalvars import *
+from ..globalvars import gc
 from ..objmethods import MMGenObject
 from ..objmethods import MMGenObject
 from ..obj import (
 from ..obj import (
 	ImmutableAttr,
 	ImmutableAttr,
@@ -85,13 +85,13 @@ class Base(MMGenObject):
 	chain        = None
 	chain        = None
 	signed       = False
 	signed       = False
 	non_mmgen_inputs_msg = f"""
 	non_mmgen_inputs_msg = f"""
-		This transaction includes inputs with non-{g.proj_name} addresses.  When
+		This transaction includes inputs with non-{gc.proj_name} addresses.  When
 		signing the transaction, private keys for the addresses listed below must
 		signing the transaction, private keys for the addresses listed below must
 		be supplied using the --keys-from-file option.  The key file must contain
 		be supplied using the --keys-from-file option.  The key file must contain
 		one key per line.  Please note that this transaction cannot be autosigned,
 		one key per line.  Please note that this transaction cannot be autosigned,
 		as autosigning does not support the use of key files.
 		as autosigning does not support the use of key files.
 
 
-		Non-{g.proj_name} addresses found in inputs:
+		Non-{gc.proj_name} addresses found in inputs:
 		    {{}}
 		    {{}}
 	"""
 	"""
 
 

+ 2 - 2
mmgen/tx/info.py

@@ -12,7 +12,7 @@
 tx.info: transaction info class
 tx.info: transaction info class
 """
 """
 
 
-from ..globalvars import *
+from ..globalvars import gc
 from ..color import red,green,orange
 from ..color import red,green,orange
 from ..opts import opt
 from ..opts import opt
 from ..util import msg,msg_r
 from ..util import msg,msg_r
@@ -43,7 +43,7 @@ class TxInfo:
 				sel_f = lambda o: len(o.mmid) + (2,8)[bool(o.is_chg)] # + len(' (chg)')
 				sel_f = lambda o: len(o.mmid) + (2,8)[bool(o.is_chg)] # + len(' (chg)')
 			return  max(max([sel_f(o) for o in io if o.mmid] or [0]),len(nonmm_str))
 			return  max(max([sel_f(o) for o in io if o.mmid] or [0]),len(nonmm_str))
 
 
-		nonmm_str = f'(non-{g.proj_name} address)'
+		nonmm_str = f'(non-{gc.proj_name} address)'
 		max_mmwid = max(get_max_mmwid(tx.inputs),get_max_mmwid(tx.outputs))
 		max_mmwid = max(get_max_mmwid(tx.inputs),get_max_mmwid(tx.outputs))
 
 
 		def gen_view():
 		def gen_view():

+ 4 - 3
mmgen/tx/new.py

@@ -15,6 +15,7 @@ tx.new: new transaction class
 from ..globalvars import *
 from ..globalvars import *
 from ..opts import opt
 from ..opts import opt
 from .base import Base
 from .base import Base
+from ..globalvars import gc
 from ..color import pink,yellow
 from ..color import pink,yellow
 from ..obj import get_obj,MMGenList
 from ..obj import get_obj,MMGenList
 from ..util import msg,qmsg,fmt,die,suf,remove_dups,get_extension
 from ..util import msg,qmsg,fmt,die,suf,remove_dups,get_extension
@@ -37,12 +38,12 @@ def mmaddr2coinaddr(mmaddr,ad_w,ad_f,proto):
 				the address into your tracking wallet before broadcasting this transaction.
 				the address into your tracking wallet before broadcasting this transaction.
 			""",
 			""",
 			'addr_not_found': f"""
 			'addr_not_found': f"""
-				No data for {g.proj_name} address {mmaddr} could be found in either the
+				No data for {gc.proj_name} address {mmaddr} could be found in either the
 				tracking wallet or the supplied address file.  Please import this address
 				tracking wallet or the supplied address file.  Please import this address
 				into your tracking wallet, or supply an address file on the command line.
 				into your tracking wallet, or supply an address file on the command line.
 			""",
 			""",
 			'addr_not_found_no_addrfile': f"""
 			'addr_not_found_no_addrfile': f"""
-				No data for {g.proj_name} address {mmaddr} could be found in the tracking
+				No data for {gc.proj_name} address {mmaddr} could be found in the tracking
 				wallet.  Please import this address into your tracking wallet or supply an
 				wallet.  Please import this address into your tracking wallet or supply an
 				address file for it on the command line.
 				address file for it on the command line.
 			"""
 			"""
@@ -227,7 +228,7 @@ class New(Base):
 				'ERROR: No change output specified' ))
 				'ERROR: No change output specified' ))
 
 
 		if self.has_segwit_outputs() and not self.rpc.info('segwit_is_active'):
 		if self.has_segwit_outputs() and not self.rpc.info('segwit_is_active'):
-			die(2,f'{g.proj_name} Segwit address requested on the command line, '
+			die(2,f'{gc.proj_name} Segwit address requested on the command line, '
 					+ 'but Segwit is not active on this chain')
 					+ 'but Segwit is not active on this chain')
 
 
 		if not self.outputs:
 		if not self.outputs:

+ 4 - 4
mmgen/tx/sign.py

@@ -20,7 +20,7 @@
 tx.sign: Sign a transaction generated by 'mmgen-txcreate'
 tx.sign: Sign a transaction generated by 'mmgen-txcreate'
 """
 """
 
 
-from ..globalvars import g
+from ..globalvars import g,gc
 from ..opts import opt
 from ..opts import opt
 from ..util import msg,vmsg,qmsg,suf,fmt,die,remove_dups,get_extension
 from ..util import msg,vmsg,qmsg,suf,fmt,die,remove_dups,get_extension
 from ..obj import MMGenList
 from ..obj import MMGenList
@@ -83,7 +83,7 @@ def add_keys(tx,src,infiles=None,saved_seeds=None,keyaddr_list=None):
 	desc,src_desc = (
 	desc,src_desc = (
 		('key-address file','From key-address file:') if keyaddr_list else
 		('key-address file','From key-address file:') if keyaddr_list else
 		('seed(s)','Generated from seed:') )
 		('seed(s)','Generated from seed:') )
-	qmsg(f'Checking {g.proj_name} -> {tx.proto.coin} address mappings for {src} (from {desc})')
+	qmsg(f'Checking {gc.proj_name} -> {tx.proto.coin} address mappings for {src} (from {desc})')
 	d = (
 	d = (
 		MMGenList([keyaddr_list]) if keyaddr_list else
 		MMGenList([keyaddr_list]) if keyaddr_list else
 		generate_kals_for_mmgen_addrs(need_keys,infiles,saved_seeds,tx.proto) )
 		generate_kals_for_mmgen_addrs(need_keys,infiles,saved_seeds,tx.proto) )
@@ -99,7 +99,7 @@ def add_keys(tx,src,infiles=None,saved_seeds=None,keyaddr_list=None):
 							new_keys.append(f)
 							new_keys.append(f)
 					else:
 					else:
 						die(3,fmt(f"""
 						die(3,fmt(f"""
-							{g.proj_name} -> {tx.proto.coin} address mappings differ!
+							{gc.proj_name} -> {tx.proto.coin} address mappings differ!
 							{{src_desc:<23}} {{mmid}} -> {{f.addr}}
 							{{src_desc:<23}} {{mmid}} -> {{f.addr}}
 							{{'tx file:':<23}} {{e.mmid}} -> {{e.addr}}
 							{{'tx file:':<23}} {{e.mmid}} -> {{e.addr}}
 							""").strip())
 							""").strip())
@@ -157,7 +157,7 @@ async def txsign(tx,seed_files,kl,kal,tx_num_str=''):
 		if missing:
 		if missing:
 			sep = '\n    '
 			sep = '\n    '
 			die(2,'ERROR: a key file must be supplied for the following non-{} address{}:{}'.format(
 			die(2,'ERROR: a key file must be supplied for the following non-{} address{}:{}'.format(
-				g.proj_name,
+				gc.proj_name,
 				suf(missing,'es'),
 				suf(missing,'es'),
 				sep + sep.join(missing) ))
 				sep + sep.join(missing) ))
 		keys += tmp.data
 		keys += tmp.data

+ 2 - 2
mmgen/ui.py

@@ -14,7 +14,7 @@ ui: Interactive user interface functions for the MMGen suite
 
 
 import sys,os
 import sys,os
 
 
-from .globalvars import g
+from .globalvars import g,gc
 from .opts import opt
 from .opts import opt
 from .util import msg,msg_r,Msg,dmsg,die
 from .util import msg,msg_r,Msg,dmsg,die
 
 
@@ -116,7 +116,7 @@ def do_pager(text):
 	end_msg = '\n(end of text)\n\n'
 	end_msg = '\n(end of text)\n\n'
 	# --- Non-MSYS Windows code deleted ---
 	# --- Non-MSYS Windows code deleted ---
 	# raw, chop, horiz scroll 8 chars, disable buggy line chopping in MSYS
 	# raw, chop, horiz scroll 8 chars, disable buggy line chopping in MSYS
-	os.environ['LESS'] = (('--shift 8 -RS'),('--shift 16 -RS'))[g.platform=='win']
+	os.environ['LESS'] = (('--shift 8 -RS'),('--shift 16 -RS'))[gc.platform=='win']
 
 
 	if 'PAGER' in os.environ and os.environ['PAGER'] != pagers[0]:
 	if 'PAGER' in os.environ and os.environ['PAGER'] != pagers[0]:
 		pagers = [os.environ['PAGER']] + pagers
 		pagers = [os.environ['PAGER']] + pagers

+ 13 - 13
mmgen/util.py

@@ -23,7 +23,7 @@ util: Frequently-used variables, classes and utility functions for the MMGen sui
 import sys,os,time,re
 import sys,os,time,re
 
 
 from .color import *
 from .color import *
-from .globalvars import g
+from .globalvars import g,gc,gv
 from .opts import opt
 from .opts import opt
 
 
 ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
 ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
@@ -32,11 +32,11 @@ hexdigits = '0123456789abcdefABCDEF'
 hexdigits_uc = '0123456789ABCDEF'
 hexdigits_uc = '0123456789ABCDEF'
 hexdigits_lc = '0123456789abcdef'
 hexdigits_lc = '0123456789abcdef'
 
 
-if g.platform == 'win':
+if gc.platform == 'win':
 	def msg_r(s):
 	def msg_r(s):
 		try:
 		try:
-			g.stderr.write(s)
-			g.stderr.flush()
+			gv.stderr.write(s)
+			gv.stderr.flush()
 		except:
 		except:
 			os.write(2,s.encode())
 			os.write(2,s.encode())
 
 
@@ -45,8 +45,8 @@ if g.platform == 'win':
 
 
 	def Msg_r(s):
 	def Msg_r(s):
 		try:
 		try:
-			g.stdout.write(s)
-			g.stdout.flush()
+			gv.stdout.write(s)
+			gv.stdout.flush()
 		except:
 		except:
 			os.write(1,s.encode())
 			os.write(1,s.encode())
 
 
@@ -54,18 +54,18 @@ if g.platform == 'win':
 		Msg_r(s + '\n')
 		Msg_r(s + '\n')
 else:
 else:
 	def msg(s):
 	def msg(s):
-		g.stderr.write(s + '\n')
+		gv.stderr.write(s + '\n')
 
 
 	def msg_r(s):
 	def msg_r(s):
-		g.stderr.write(s)
-		g.stderr.flush()
+		gv.stderr.write(s)
+		gv.stderr.flush()
 
 
 	def Msg(s):
 	def Msg(s):
-		g.stdout.write(s + '\n')
+		gv.stdout.write(s + '\n')
 
 
 	def Msg_r(s):
 	def Msg_r(s):
-		g.stdout.write(s)
-		g.stdout.flush()
+		gv.stdout.write(s)
+		gv.stdout.flush()
 
 
 def rmsg(s):
 def rmsg(s):
 	msg(red(s))
 	msg(red(s))
@@ -413,5 +413,5 @@ def wrap_ripemd160(called=[]):
 		called.append(True)
 		called.append(True)
 
 
 def exit_if_mswin(feature):
 def exit_if_mswin(feature):
-	if g.platform == 'win':
+	if gc.platform == 'win':
 		die(2, capfirst(feature) + ' not supported on the MSWin / MSYS2 platform' )
 		die(2, capfirst(feature) + ' not supported on the MSWin / MSYS2 platform' )

+ 2 - 2
mmgen/wallet/enc.py

@@ -12,7 +12,7 @@
 wallet.enc: encrypted wallet base class
 wallet.enc: encrypted wallet base class
 """
 """
 
 
-from ..globalvars import g
+from ..globalvars import gc
 from ..opts import opt
 from ..opts import opt
 from ..util import msg,qmsg,make_chksum_8
 from ..util import msg,qmsg,make_chksum_8
 from .base import wallet
 from .base import wallet
@@ -60,7 +60,7 @@ class wallet(wallet):
 			qmsg(f'Using hash preset {hp!r} requested on command line')
 			qmsg(f'Using hash preset {hp!r} requested on command line')
 		else:
 		else:
 			hp = self._get_hash_preset_from_user(
 			hp = self._get_hash_preset_from_user(
-				old_preset = g.dfl_hash_preset,
+				old_preset = gc.dfl_hash_preset,
 				add_desc   = add_desc )
 				add_desc   = add_desc )
 		self.ssdata.hash_preset = hp
 		self.ssdata.hash_preset = hp
 
 

+ 3 - 3
mmgen/wallet/incog_hidden.py

@@ -14,7 +14,7 @@ wallet.incog_hidden: hidden incognito wallet class
 
 
 import os
 import os
 
 
-from ..globalvars import g
+from ..globalvars import gc
 from ..opts import opt
 from ..opts import opt
 from ..seed import Seed
 from ..seed import Seed
 from ..util import msg,dmsg,qmsg,die,compare_or_die,capfirst
 from ..util import msg,dmsg,qmsg,die,compare_or_die,capfirst
@@ -74,7 +74,7 @@ class wallet(wallet):
 		d.target_data_len = self._get_incog_data_len(opt.seed_len or Seed.dfl_len)
 		d.target_data_len = self._get_incog_data_len(opt.seed_len or Seed.dfl_len)
 		self._check_valid_offset(self.infile,'read')
 		self._check_valid_offset(self.infile,'read')
 
 
-		flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY
+		flgs = os.O_RDONLY|os.O_BINARY if gc.platform == 'win' else os.O_RDONLY
 		fh = os.open(self.infile.name,flgs)
 		fh = os.open(self.infile.name,flgs)
 		os.lseek(fh,int(d.hincog_offset),os.SEEK_SET)
 		os.lseek(fh,int(d.hincog_offset),os.SEEK_SET)
 		self.fmt_data = os.read(fh,d.target_data_len)
 		self.fmt_data = os.read(fh,d.target_data_len)
@@ -135,7 +135,7 @@ class wallet(wallet):
 					message = '',
 					message = '',
 					action  = f'alter file {f.name!r}' )
 					action  = f'alter file {f.name!r}' )
 
 
-		flgs = os.O_RDWR|os.O_BINARY if g.platform == 'win' else os.O_RDWR
+		flgs = os.O_RDWR|os.O_BINARY if gc.platform == 'win' else os.O_RDWR
 		fh = os.open(f.name,flgs)
 		fh = os.open(f.name,flgs)
 		os.lseek(fh, int(d.hincog_offset), os.SEEK_SET)
 		os.lseek(fh, int(d.hincog_offset), os.SEEK_SET)
 		os.write(fh, self.fmt_data)
 		os.write(fh, self.fmt_data)

+ 2 - 2
scripts/uninstall-mmgen.py

@@ -19,7 +19,7 @@
 import sys,os
 import sys,os
 
 
 import mmgen.opts as opts
 import mmgen.opts as opts
-from mmgen.globalvars import g
+from mmgen.globalvars import gc
 from mmgen.util import msg,die
 from mmgen.util import msg,die
 
 
 def normalize_path(p):
 def normalize_path(p):
@@ -53,7 +53,7 @@ opts_data = {
 
 
 cmd_args = opts.init(opts_data)
 cmd_args = opts.init(opts_data)
 
 
-if g.platform == 'linux' and os.getenv('USER') != 'root':
+if gc.platform == 'linux' and os.getenv('USER') != 'root':
 	die(1,'This program must be run as root')
 	die(1,'This program must be run as root')
 
 
 if len(cmd_args):
 if len(cmd_args):

+ 2 - 2
test/gentest.py

@@ -28,7 +28,7 @@ sys.path.insert(0,overlay_setup(repo_root))
 
 
 # Import these _after_ local path's been added to sys.path
 # Import these _after_ local path's been added to sys.path
 import mmgen.opts as opts
 import mmgen.opts as opts
-from mmgen.globalvars import g
+from mmgen.globalvars import g,gc
 from mmgen.opts import opt
 from mmgen.opts import opt
 from mmgen.color import green,red,purple
 from mmgen.color import green,red,purple
 from mmgen.util import msg,qmsg,qmsg_r,vmsg,capfirst,is_int,die
 from mmgen.util import msg,qmsg,qmsg_r,vmsg,capfirst,is_int,die
@@ -131,7 +131,7 @@ SUPPORTED EXTERNAL TOOLS:
 		),
 		),
 		'notes': lambda s: s.format(
 		'notes': lambda s: s.format(
 			prog='test/gentest.py',
 			prog='test/gentest.py',
-			pnm=g.proj_name,
+			pnm=gc.proj_name,
 			snum=rounds )
 			snum=rounds )
 	}
 	}
 }
 }

+ 2 - 2
test/include/coin_daemon_control.py

@@ -15,7 +15,7 @@ test.include.coin_daemon_control: Start and stop daemons for the MMGen test suit
 from .tests_header import repo_root
 from .tests_header import repo_root
 from mmgen.common import *
 from mmgen.common import *
 
 
-action = g.prog_name.split('-')[0]
+action = gc.prog_name.split('-')[0]
 
 
 opts_data = {
 opts_data = {
 	'sets': [('debug',True,'verbose',True)],
 	'sets': [('debug',True,'verbose',True)],
@@ -44,7 +44,7 @@ Valid network IDs: {nid}, all, or no_xmr
 """
 """
 	},
 	},
 	'code': {
 	'code': {
-		'options': lambda s: s.format(a=action.capitalize(),pn=g.prog_name),
+		'options': lambda s: s.format(a=action.capitalize(),pn=gc.prog_name),
 		'notes': lambda s,help_notes: s.format(nid=help_notes('coin_daemon_network_ids'))
 		'notes': lambda s,help_notes: s.format(nid=help_notes('coin_daemon_network_ids'))
 	}
 	}
 }
 }

+ 4 - 4
test/include/common.py

@@ -162,13 +162,13 @@ def init_coverage():
 
 
 def silence():
 def silence():
 	if not (opt.verbose or opt.exact_output):
 	if not (opt.verbose or opt.exact_output):
-		g.stdout = g.stderr = open(os.devnull,'w')
+		gv.stdout = gv.stderr = open(os.devnull,'w')
 
 
 def end_silence():
 def end_silence():
 	if not (opt.verbose or opt.exact_output):
 	if not (opt.verbose or opt.exact_output):
-		g.stdout.close()
-		g.stdout = sys.stdout
-		g.stderr = sys.stderr
+		gv.stdout.close()
+		gv.stdout = sys.stdout
+		gv.stderr = sys.stderr
 
 
 def omsg(s):
 def omsg(s):
 	sys.stderr.write(s + '\n')
 	sys.stderr.write(s + '\n')

+ 1 - 1
test/misc/get_passphrase.py

@@ -29,7 +29,7 @@ def crypto():
 	from mmgen.crypto import Crypto
 	from mmgen.crypto import Crypto
 	crypto = Crypto()
 	crypto = Crypto()
 
 
-	pw = crypto.get_new_passphrase(data_desc=desc,hash_preset=g.dfl_hash_preset,passwd_file=None)
+	pw = crypto.get_new_passphrase(data_desc=desc,hash_preset=gc.dfl_hash_preset,passwd_file=None)
 	msg(f'==> got new passphrase: [{pw}]\n')
 	msg(f'==> got new passphrase: [{pw}]\n')
 
 
 	pw = crypto.get_passphrase(data_desc=desc,passwd_file=None)
 	pw = crypto.get_passphrase(data_desc=desc,passwd_file=None)

+ 5 - 5
test/misc/term.py

@@ -19,13 +19,13 @@ commands = [
 	'get_char_one',
 	'get_char_one',
 	'get_char_one_raw',
 	'get_char_one_raw',
 ]
 ]
-if g.platform == 'linux':
+if gc.platform == 'linux':
 	commands.extend([
 	commands.extend([
 		'get_char',
 		'get_char',
 		'get_char_immed_chars',
 		'get_char_immed_chars',
 		'get_char_raw',
 		'get_char_raw',
 	])
 	])
-elif g.platform == 'win':
+elif gc.platform == 'win':
 	commands.extend([
 	commands.extend([
 		'get_char_one_char_immed_chars',
 		'get_char_one_char_immed_chars',
 	])
 	])
@@ -38,7 +38,7 @@ opts_data = {
 -h, --help     Print this help message
 -h, --help     Print this help message
 """,
 """,
 	'notes': f"""
 	'notes': f"""
-available commands for platform {g.platform!r}:
+available commands for platform {gc.platform!r}:
 {fmt_list(commands,fmt='col',indent='    ')}
 {fmt_list(commands,fmt='col',indent='    ')}
 """
 """
 	}
 	}
@@ -118,7 +118,7 @@ def _tt_get_char(raw=False,one_char=False,immed_chars=''):
 			if one_char else
 			if one_char else
 		'echoed as a FULL CONTROL SEQUENCE.'
 		'echoed as a FULL CONTROL SEQUENCE.'
 	)
 	)
-	if g.platform == 'win':
+	if gc.platform == 'win':
 		if raw:
 		if raw:
 			m3 = 'The Escape and F1-F12 keys will be returned as two-character strings.'
 			m3 = 'The Escape and F1-F12 keys will be returned as two-character strings.'
 		else:
 		else:
@@ -149,7 +149,7 @@ def tt_urand():
 	msg(f'USER ENTROPY (user input + keystroke timings):\n\n{fmt(ret,"  ")}')
 	msg(f'USER ENTROPY (user input + keystroke timings):\n\n{fmt(ret,"  ")}')
 	times = ret.splitlines()[1:]
 	times = ret.splitlines()[1:]
 	avg_prec = sum(len(t.split('.')[1]) for t in times) // len(times)
 	avg_prec = sum(len(t.split('.')[1]) for t in times) // len(times)
-	if avg_prec < g.min_time_precision:
+	if avg_prec < gc.min_time_precision:
 		ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points.  User entropy quality is degraded!')
 		ymsg(f'WARNING: Avg. time precision of only {avg_prec} decimal points.  User entropy quality is degraded!')
 	else:
 	else:
 		msg(f'Average time precision: {avg_prec} decimal points - OK')
 		msg(f'Average time precision: {avg_prec} decimal points - OK')

+ 1 - 1
test/scrambletest.py

@@ -127,7 +127,7 @@ def do_coin_tests():
 	for tname,tdata in (
 	for tname,tdata in (
 			tuple(bitcoin_data.items()) +
 			tuple(bitcoin_data.items()) +
 			tuple(altcoin_data.items() if not opt.no_altcoin else []) ):
 			tuple(altcoin_data.items() if not opt.no_altcoin else []) ):
-		if tname == 'zec_zcash_z' and g.platform == 'win':
+		if tname == 'zec_zcash_z' and gc.platform == 'win':
 			msg("Skipping 'zec_zcash_z' test for Windows platform")
 			msg("Skipping 'zec_zcash_z' test for Windows platform")
 			continue
 			continue
 		coin,mmtype = tname.split('_',1) if '_' in tname else (tname,None)
 		coin,mmtype = tname.split('_',1) if '_' in tname else (tname,None)

+ 6 - 6
test/test.py

@@ -30,7 +30,7 @@ def create_shm_dir(data_dir,trash_dir):
 	# under '/dev/shm' and put datadir and tmpdirs here.
 	# under '/dev/shm' and put datadir and tmpdirs here.
 	import shutil
 	import shutil
 	from subprocess import run
 	from subprocess import run
-	if g.platform == 'win':
+	if gc.platform == 'win':
 		for tdir in (data_dir,trash_dir):
 		for tdir in (data_dir,trash_dir):
 			try: os.listdir(tdir)
 			try: os.listdir(tdir)
 			except: pass
 			except: pass
@@ -195,7 +195,7 @@ opts.UserOpts._reset_ok += (
 parsed_opts = opts.init(opts_data,return_parsed=True)
 parsed_opts = opts.init(opts_data,return_parsed=True)
 usr_args = parsed_opts.cmd_args
 usr_args = parsed_opts.cmd_args
 
 
-if opt.pexpect_spawn and g.platform == 'win':
+if opt.pexpect_spawn and gc.platform == 'win':
 	die(1,'--pexpect-spawn option not supported on Windows platform, exiting')
 	die(1,'--pexpect-spawn option not supported on Windows platform, exiting')
 
 
 if opt.daemon_id and opt.daemon_id in g.blacklisted_daemons.split():
 if opt.daemon_id and opt.daemon_id in g.blacklisted_daemons.split():
@@ -313,7 +313,7 @@ def clean(usr_dirs=None,clean_overlay=True):
 		iqmsg(green(f'Cleaned directory {os.path.relpath(overlay_tree_dir)!r}'))
 		iqmsg(green(f'Cleaned directory {os.path.relpath(overlay_tree_dir)!r}'))
 
 
 def create_tmp_dirs(shm_dir):
 def create_tmp_dirs(shm_dir):
-	if g.platform == 'win':
+	if gc.platform == 'win':
 		for cfg in sorted(cfgs):
 		for cfg in sorted(cfgs):
 			mk_tmpdir(cfgs[cfg]['tmpdir'])
 			mk_tmpdir(cfgs[cfg]['tmpdir'])
 	else:
 	else:
@@ -556,7 +556,7 @@ class TestSuiteRunner(object):
 			omsg(f'INFO → Writing coverage files to {coverdir!r}')
 			omsg(f'INFO → Writing coverage files to {coverdir!r}')
 			self.pre_args = ['python3','-m','trace','--count','--coverdir='+coverdir,'--file='+accfile]
 			self.pre_args = ['python3','-m','trace','--count','--coverdir='+coverdir,'--file='+accfile]
 		else:
 		else:
-			self.pre_args = ['python3'] if g.platform == 'win' else []
+			self.pre_args = ['python3'] if gc.platform == 'win' else []
 
 
 		if opt.pexpect_spawn:
 		if opt.pexpect_spawn:
 			omsg(f'INFO → Using pexpect.spawn() for real terminal emulation')
 			omsg(f'INFO → Using pexpect.spawn() for real terminal emulation')
@@ -612,7 +612,7 @@ class TestSuiteRunner(object):
 					clr1,clr2 = (nocolor,nocolor) if opt.print_cmdline else (green,cyan)
 					clr1,clr2 = (nocolor,nocolor) if opt.print_cmdline else (green,cyan)
 					omsg(
 					omsg(
 						clr1('Executing: ') +
 						clr1('Executing: ') +
-						clr2(repr(cmd_disp) if g.platform == 'win' else cmd_disp)
+						clr2(repr(cmd_disp) if gc.platform == 'win' else cmd_disp)
 					)
 					)
 			else:
 			else:
 				omsg_r(f'{t_pfx}Testing {desc}: ')
 				omsg_r(f'{t_pfx}Testing {desc}: ')
@@ -918,7 +918,7 @@ class TestSuiteRunner(object):
 
 
 	def check_deps(self,cmds): # TODO: broken
 	def check_deps(self,cmds): # TODO: broken
 		if len(cmds) != 1:
 		if len(cmds) != 1:
-			die(1,f'Usage: {g.prog_name} check_deps <command>')
+			die(1,f'Usage: {gc.prog_name} check_deps <command>')
 
 
 		cmd = cmds[0]
 		cmd = cmds[0]
 
 

+ 4 - 3
test/test_py_d/common.py

@@ -20,8 +20,9 @@
 test.test_py_d.common: Shared routines and data for the test.py test suite
 test.test_py_d.common: Shared routines and data for the test.py test suite
 """
 """
 
 
-import os
-from mmgen.common import *
+import sys,os
+from mmgen.globalvars import g,gc
+from mmgen.util import msg
 from ..include.common import *
 from ..include.common import *
 
 
 log_file = 'test.py.log'
 log_file = 'test.py.log'
@@ -53,7 +54,7 @@ from mmgen.obj import MMGenTxComment,TwComment
 tx_comment_jp = text_jp
 tx_comment_jp = text_jp
 tx_comment_zh = text_zh
 tx_comment_zh = text_zh
 
 
-lcg = ascii_cyr_gr if g.platform == 'win' else lat_cyr_gr # MSYS2 popen_spawn issue
+lcg = ascii_cyr_gr if gc.platform == 'win' else lat_cyr_gr # MSYS2 popen_spawn issue
 tx_comment_lat_cyr_gr = lcg[:MMGenTxComment.max_len] # 72 chars
 tx_comment_lat_cyr_gr = lcg[:MMGenTxComment.max_len] # 72 chars
 
 
 tw_comment_zh         = text_zh[:TwComment.max_screen_width // 2]
 tw_comment_zh         = text_zh[:TwComment.max_screen_width // 2]

+ 3 - 3
test/test_py_d/ts_autosign.py

@@ -23,7 +23,7 @@ test.test_py_d.ts_autosign: Autosign tests for the test.py test suite
 import os,shutil
 import os,shutil
 from subprocess import run
 from subprocess import run
 
 
-from mmgen.globalvars import g
+from mmgen.globalvars import g,gc
 from mmgen.opts import opt
 from mmgen.opts import opt
 
 
 from ..include.common import *
 from ..include.common import *
@@ -84,7 +84,7 @@ class TestSuiteAutosignBase(TestSuiteBase):
 		super().__init__(trunner,cfgs,spawn)
 		super().__init__(trunner,cfgs,spawn)
 		if trunner == None:
 		if trunner == None:
 			return
 			return
-		if g.platform == 'win':
+		if gc.platform == 'win':
 			die(1,f'Test {type(self).__name__} not supported for Windows platform')
 			die(1,f'Test {type(self).__name__} not supported for Windows platform')
 		self.network_ids = [c+'_tn' for c in self.daemon_coins] + self.daemon_coins
 		self.network_ids = [c+'_tn' for c in self.daemon_coins] + self.daemon_coins
 
 
@@ -126,7 +126,7 @@ class TestSuiteAutosignBase(TestSuiteBase):
 		self.bad_msg_count = 0
 		self.bad_msg_count = 0
 
 
 	def __del__(self):
 	def __del__(self):
-		if g.platform == 'win' or self.tr == None:
+		if gc.platform == 'win' or self.tr == None:
 			return
 			return
 		if self.simulate or not self.live:
 		if self.simulate or not self.live:
 			LEDControl.delete_dummy_control_files()
 			LEDControl.delete_dummy_control_files()

+ 2 - 2
test/test_py_d/ts_base.py

@@ -21,7 +21,7 @@ test.test_py_d.ts_base: Base class for the test.py test suite
 """
 """
 
 
 import os
 import os
-from mmgen.globalvars import g
+from mmgen.globalvars import g,gc
 from mmgen.opts import opt
 from mmgen.opts import opt
 from ..include.common import *
 from ..include.common import *
 from .common import *
 from .common import *
@@ -74,7 +74,7 @@ class TestSuiteBase(object):
 		return write_to_file(os.path.join(self.tmpdir,fn),data,binary=binary)
 		return write_to_file(os.path.join(self.tmpdir,fn),data,binary=binary)
 
 
 	def skip_for_win(self):
 	def skip_for_win(self):
-		if g.platform == 'win':
+		if gc.platform == 'win':
 			msg(f'Skipping test {self.test_name!r}: not supported on MSys2 platform')
 			msg(f'Skipping test {self.test_name!r}: not supported on MSys2 platform')
 			return True
 			return True
 		else:
 		else:

+ 1 - 1
test/test_py_d/ts_cfgfile.py

@@ -158,7 +158,7 @@ class TestSuiteCfgFile(TestSuiteBase):
 		write_to_file(self.path('usr'),'\n'.join(d) + '\n')
 		write_to_file(self.path('usr'),'\n'.join(d) + '\n')
 		return self.old_sample_common(
 		return self.old_sample_common(
 			old_set       = True,
 			old_set       = True,
-			pexpect_spawn = False if g.platform == 'win' else True )
+			pexpect_spawn = False if gc.platform == 'win' else True )
 
 
 	def _autoset_opts(self,args=[],text='rpc_backend aiohttp\n'):
 	def _autoset_opts(self,args=[],text='rpc_backend aiohttp\n'):
 		write_to_file( self.path('usr'), text )
 		write_to_file( self.path('usr'), text )

+ 2 - 2
test/test_py_d/ts_ethdev.py

@@ -25,7 +25,7 @@ from decimal import Decimal
 from collections import namedtuple
 from collections import namedtuple
 from subprocess import run,PIPE,DEVNULL
 from subprocess import run,PIPE,DEVNULL
 
 
-from mmgen.globalvars import g
+from mmgen.globalvars import g,gc
 from mmgen.opts import opt
 from mmgen.opts import opt
 from mmgen.util import die
 from mmgen.util import die
 from mmgen.protocol import CoinProtocol
 from mmgen.protocol import CoinProtocol
@@ -1290,7 +1290,7 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 	def edit_comment1(self):
 	def edit_comment1(self):
 		return self.edit_comment(out_num=del_addrs[0],comment_text=tw_comment_zh[:3])
 		return self.edit_comment(out_num=del_addrs[0],comment_text=tw_comment_zh[:3])
 	def edit_comment2(self):
 	def edit_comment2(self):
-		spawn = False if g.platform == 'win' else True
+		spawn = False if gc.platform == 'win' else True
 		return self.edit_comment(out_num=del_addrs[0],comment_text=tw_comment_zh[3:],changed=True,pexpect_spawn=spawn)
 		return self.edit_comment(out_num=del_addrs[0],comment_text=tw_comment_zh[3:],changed=True,pexpect_spawn=spawn)
 	def edit_comment3(self):
 	def edit_comment3(self):
 		return self.edit_comment(out_num=del_addrs[1],comment_text=tw_comment_lat_cyr_gr)
 		return self.edit_comment(out_num=del_addrs[1],comment_text=tw_comment_lat_cyr_gr)

+ 4 - 4
test/test_py_d/ts_input.py

@@ -219,12 +219,12 @@ class TestSuiteInput(TestSuiteBase):
 
 
 		# hash preset (default)
 		# hash preset (default)
 		t.expect('accept the default .*: ', '\n', regex=True)
 		t.expect('accept the default .*: ', '\n', regex=True)
-		t.expect(f'[{g.dfl_hash_preset}]')
+		t.expect(f'[{gc.dfl_hash_preset}]')
 
 
 		return t
 		return t
 
 
 	def _input_func(self,func_name,arg_dfls,func_args,text,expect,term):
 	def _input_func(self,func_name,arg_dfls,func_args,text,expect,term):
-		if term and g.platform == 'win':
+		if term and gc.platform == 'win':
 			return ('skip_warn','pexpect_spawn not supported on Windows platform')
 			return ('skip_warn','pexpect_spawn not supported on Windows platform')
 		func_args = {k:v for k,v in zip(arg_dfls.keys(),func_args)}
 		func_args = {k:v for k,v in zip(arg_dfls.keys(),func_args)}
 		t = self.spawn(
 		t = self.spawn(
@@ -268,7 +268,7 @@ class TestSuiteInput(TestSuiteBase):
 		return self._get_char(['prompt> ','',True,5],'x','x',False)
 		return self._get_char(['prompt> ','',True,5],'x','x',False)
 
 
 	def get_char2(self):
 	def get_char2(self):
-		expect = 'x' if g.platform == 'win' else 'xxxxx'
+		expect = 'x' if gc.platform == 'win' else 'xxxxx'
 		return self._get_char(['prompt> ','',True,5],'xxxxx',expect,False)
 		return self._get_char(['prompt> ','',True,5],'xxxxx',expect,False)
 
 
 	def get_char3(self):
 	def get_char3(self):
@@ -314,7 +314,7 @@ class TestSuiteInput(TestSuiteBase):
 		return self._line_input(['prompt> ',True,'foobarbaz',True],Ctrl_U+'foobar','foobar',True)
 		return self._line_input(['prompt> ',True,'foobarbaz',True],Ctrl_U+'foobar','foobar',True)
 
 
 	def _password_entry(self,prompt,opts=[],term=False):
 	def _password_entry(self,prompt,opts=[],term=False):
-		if term and g.platform == 'win':
+		if term and gc.platform == 'win':
 			return ('skip_warn','pexpect_spawn not supported on Windows platform')
 			return ('skip_warn','pexpect_spawn not supported on Windows platform')
 		t = self.spawn( 'test/misc/input_func.py', opts + ['passphrase'], cmd_dir='.', pexpect_spawn=term )
 		t = self.spawn( 'test/misc/input_func.py', opts + ['passphrase'], cmd_dir='.', pexpect_spawn=term )
 		imsg('Terminal: {}'.format(term))
 		imsg('Terminal: {}'.format(term))

+ 2 - 2
test/test_py_d/ts_misc.py

@@ -20,7 +20,7 @@
 test.test_py_d.ts_misc: Miscellaneous test groups for the test.py test suite
 test.test_py_d.ts_misc: Miscellaneous test groups for the test.py test suite
 """
 """
 
 
-from mmgen.globalvars import g
+from mmgen.globalvars import g,gc
 from ..include.common import *
 from ..include.common import *
 from .common import *
 from .common import *
 from .ts_base import *
 from .ts_base import *
@@ -233,7 +233,7 @@ class TestSuiteOutput(TestSuiteBase):
 
 
 	def oneshot_warning(self,pexpect_spawn=None):
 	def oneshot_warning(self,pexpect_spawn=None):
 		t = self.spawn('test/misc/oneshot_warning.py',cmd_dir='.',pexpect_spawn=pexpect_spawn)
 		t = self.spawn('test/misc/oneshot_warning.py',cmd_dir='.',pexpect_spawn=pexpect_spawn)
-		nl = '\r\n' if g.platform == 'win' or t.pexpect_spawn else '\n'
+		nl = '\r\n' if gc.platform == 'win' or t.pexpect_spawn else '\n'
 		for s in (
 		for s in (
 			f'pw{nl}wg1',
 			f'pw{nl}wg1',
 			'foo is experimental',
 			'foo is experimental',

+ 1 - 1
test/test_py_d/ts_tool.py

@@ -74,7 +74,7 @@ class TestSuiteTool(TestSuiteMain,TestSuiteBase):
 		vmsg(f'Incog ID: {cyan(i_id)}')
 		vmsg(f'Incog ID: {cyan(i_id)}')
 		t = self.spawn('mmgen-tool',['-d',self.tmpdir,'find_incog_data',f1,i_id])
 		t = self.spawn('mmgen-tool',['-d',self.tmpdir,'find_incog_data',f1,i_id])
 		o = t.expect_getend(f'Incog data for ID {i_id} found at offset ')
 		o = t.expect_getend(f'Incog data for ID {i_id} found at offset ')
-		if not g.platform == 'win':
+		if not gc.platform == 'win':
 			os.unlink(f1) # causes problems with MSYS2
 			os.unlink(f1) # causes problems with MSYS2
 		cmp_or_die(hincog_offset,int(o))
 		cmp_or_die(hincog_offset,int(o))
 		return t
 		return t

+ 2 - 2
test/test_py_d/ts_xmrwallet.py

@@ -23,7 +23,7 @@ test.test_py_d.ts_xmrwallet: xmrwallet tests for the test.py test suite
 import sys,os,atexit,asyncio,shutil
 import sys,os,atexit,asyncio,shutil
 from subprocess import run,PIPE
 from subprocess import run,PIPE
 
 
-from mmgen.globalvars import g
+from mmgen.globalvars import gc
 from mmgen.opts import opt
 from mmgen.opts import opt
 from mmgen.obj import MMGenRange
 from mmgen.obj import MMGenRange
 from mmgen.amt import XMRAmt
 from mmgen.amt import XMRAmt
@@ -128,7 +128,7 @@ class TestSuiteXMRWallet(TestSuiteBase):
 				omsg(f'SSH SOCKS server started, listening at localhost:{cls.socks_port}')
 				omsg(f'SSH SOCKS server started, listening at localhost:{cls.socks_port}')
 
 
 		def kill_proxy():
 		def kill_proxy():
-			if g.platform == 'linux':
+			if gc.platform == 'linux':
 				omsg(f'Killing SSH SOCKS server at localhost:{cls.socks_port}')
 				omsg(f'Killing SSH SOCKS server at localhost:{cls.socks_port}')
 				cmd = [ 'pkill', '-f', ' '.join(a + b2) ]
 				cmd = [ 'pkill', '-f', ' '.join(a + b2) ]
 				run(cmd)
 				run(cmd)

+ 1 - 1
test/tooltest.py

@@ -141,7 +141,7 @@ spawn_cmd = ['scripts/exec_wrapper.py',mmgen_cmd]
 if opt.coverage:
 if opt.coverage:
 	d,f = init_coverage()
 	d,f = init_coverage()
 	spawn_cmd = ['python3','-m','trace','--count','--coverdir='+d,'--file='+f] + spawn_cmd
 	spawn_cmd = ['python3','-m','trace','--count','--coverdir='+d,'--file='+f] + spawn_cmd
-elif g.platform == 'win':
+elif gc.platform == 'win':
 	spawn_cmd = ['python3'] + spawn_cmd
 	spawn_cmd = ['python3'] + spawn_cmd
 
 
 add_spawn_args = ['--data-dir='+cfg['tmpdir']] + ['--{}{}'.format(
 add_spawn_args = ['--data-dir='+cfg['tmpdir']] + ['--{}{}'.format(

+ 2 - 2
test/tooltest2.py

@@ -40,7 +40,7 @@ from mmgen.baseconv import *
 
 
 skipped_tests = ['mn2hex_interactive']
 skipped_tests = ['mn2hex_interactive']
 
 
-NL = ('\n','\r\n')[g.platform=='win']
+NL = ('\n','\r\n')[gc.platform=='win']
 
 
 def is_str(s):
 def is_str(s):
 	return type(s) == str
 	return type(s) == str
@@ -866,7 +866,7 @@ async def run_test(cls,gid,cmd_name):
 		elif opt.fork:
 		elif opt.fork:
 			cmd_out = fork_cmd(cmd_name,args,out,opts,stdin_input)
 			cmd_out = fork_cmd(cmd_name,args,out,opts,stdin_input)
 		else:
 		else:
-			if stdin_input and g.platform == 'win':
+			if stdin_input and gc.platform == 'win':
 				msg('Skipping for MSWin - no os.fork()')
 				msg('Skipping for MSWin - no os.fork()')
 				continue
 				continue
 			method = getattr(cls(cmdname=cmd_name,proto=proto,mmtype=mmtype),cmd_name)
 			method = getattr(cls(cmdname=cmd_name,proto=proto,mmtype=mmtype),cmd_name)

+ 1 - 1
test/unit_tests.py

@@ -142,7 +142,7 @@ def run_test(test,subtest=None):
 				if opt.no_altcoin_deps and subtest in altcoin_deps:
 				if opt.no_altcoin_deps and subtest in altcoin_deps:
 					qmsg(gray(f'Invoked with --no-altcoin-deps, so skipping {subtest_disp!r}'))
 					qmsg(gray(f'Invoked with --no-altcoin-deps, so skipping {subtest_disp!r}'))
 					continue
 					continue
-				if g.platform == 'win' and subtest in win_skip:
+				if gc.platform == 'win' and subtest in win_skip:
 					qmsg(gray(f'Skipping {subtest_disp!r} for Windows platform'))
 					qmsg(gray(f'Skipping {subtest_disp!r} for Windows platform'))
 					continue
 					continue
 				elif platform.machine() == 'aarch64' and subtest in arm_skip:
 				elif platform.machine() == 'aarch64' and subtest in arm_skip:

+ 4 - 4
test/unit_tests_d/__init__.py

@@ -6,7 +6,7 @@ test.unit_tests_d.__init__: shared data for unit tests for the MMGen suite
 
 
 import sys,os
 import sys,os
 
 
-from mmgen.globalvars import g
+from mmgen.globalvars import gv
 from mmgen.opts import opt
 from mmgen.opts import opt
 
 
 class unit_tests_base:
 class unit_tests_base:
@@ -15,9 +15,9 @@ class unit_tests_base:
 		if not opt.verbose:
 		if not opt.verbose:
 			self.stdout = sys.stdout
 			self.stdout = sys.stdout
 			self.stderr = sys.stderr
 			self.stderr = sys.stderr
-			sys.stdout = sys.stderr = g.stdout = g.stderr = open(os.devnull,'w')
+			sys.stdout = sys.stderr = gv.stdout = gv.stderr = open(os.devnull,'w')
 
 
 	def _end_silence(self):
 	def _end_silence(self):
 		if not opt.verbose:
 		if not opt.verbose:
-			sys.stdout = g.stdout = self.stdout
-			sys.stderr = g.stderr = self.stderr
+			sys.stdout = gv.stdout = self.stdout
+			sys.stderr = gv.stderr = self.stderr

+ 1 - 1
test/unit_tests_d/ut_rpc.py

@@ -120,7 +120,7 @@ def run_test(network_ids,test_cf_auth=False,daemon_ids=None):
 		if not opt.no_daemon_stop:
 		if not opt.no_daemon_stop:
 			d.stop()
 			d.stop()
 
 
-		if test_cf_auth and g.platform != 'win':
+		if test_cf_auth and gc.platform != 'win':
 			cfg_file_auth_test(d.proto,d)
 			cfg_file_auth_test(d.proto,d)
 			cfg_file_auth_test(d.proto,d,bad_auth=True)
 			cfg_file_auth_test(d.proto,d,bad_auth=True)
 
 

+ 1 - 1
test/unit_tests_d/ut_testdep.py

@@ -48,7 +48,7 @@ class unit_tests:
 		return True
 		return True
 
 
 	def ethkey(self,name,ut):
 	def ethkey(self,name,ut):
-		if g.platform == 'linux' and os.uname().machine != 'x86_64':
+		if gc.platform == 'linux' and os.uname().machine != 'x86_64':
 			distro = [l for l in open('/etc/os-release').read().split('\n') if l.startswith('ID=')][0][3:]
 			distro = [l for l in open('/etc/os-release').read().split('\n') if l.startswith('ID=')][0][3:]
 			if distro != 'archarm':
 			if distro != 'archarm':
 				ymsg('Skipping ethkey availability test for distro {!r} on architecture {!r}'.format(
 				ymsg('Skipping ethkey availability test for distro {!r} on architecture {!r}'.format(