Browse Source

protocol.py: new coin protocol instance attrs

- add 'testnet', 'regtest' and 'dcoin' attributes to coin protocol instance,
  remove is_testnet() method

- g.testnet -> g.proto.testnet, g.regtest -> g.proto.regtest

- g.coin and g.dcoin are now read-only properties shadowing g.proto.coin
  and g.proto.dcoin, respectively
The MMGen Project 4 years ago
parent
commit
31f7236731

+ 7 - 7
mmgen/addr.py

@@ -487,7 +487,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 
 	def scramble_seed(self,seed):
 		is_btcfork = g.proto.base_coin == 'BTC'
-		if is_btcfork and self.al_id.mmtype == 'L' and not g.proto.is_testnet():
+		if is_btcfork and self.al_id.mmtype == 'L' and not g.proto.testnet:
 			dmsg_sc('str','(none)')
 			return seed
 		if g.proto.base_coin == 'ETH':
@@ -495,7 +495,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 		else:
 			scramble_key = (g.coin.lower()+':','')[is_btcfork] + self.al_id.mmtype.name
 		from .crypto import scramble_seed
-		if g.proto.is_testnet():
+		if g.proto.testnet:
 			scramble_key += ':testnet'
 		dmsg_sc('str',scramble_key)
 		return scramble_seed(seed,scramble_key.encode())
@@ -506,7 +506,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 		self.ext += '.'+g.mmenc_ext
 
 	def write_to_file(self,ask_tty=True,ask_write_default_yes=False,binary=False,desc=None):
-		tn = ('','.testnet')[g.proto.is_testnet()]
+		tn = ('','.testnet')[g.proto.testnet]
 		fn = '{}{x}{}.{}'.format(self.id_str,tn,self.ext,x='-α' if g.debug_utf8 else '')
 		ask_tty = self.has_keys and not opt.quiet
 		write_data_to_file(fn,self.fmt_data,desc or self.file_desc,ask_tty=ask_tty,binary=binary)
@@ -588,8 +588,8 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 	def make_label(self):
 		bc,mt = g.proto.base_coin,self.al_id.mmtype
 		l_coin = [] if bc == 'BTC' else [g.coin] if bc == 'ETH' else [bc]
-		l_type = [] if mt == 'E' or (mt == 'L' and not g.proto.is_testnet()) else [mt.name.upper()]
-		l_tn   = [] if not g.proto.is_testnet() else ['TESTNET']
+		l_type = [] if mt == 'E' or (mt == 'L' and not g.proto.testnet) else [mt.name.upper()]
+		l_tn   = [] if not g.proto.testnet else ['TESTNET']
 		lbl_p2 = ':'.join(l_coin+l_type+l_tn)
 		return self.al_id.sid + ('',' ')[bool(lbl_p2)] + lbl_p2
 
@@ -678,10 +678,10 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 			al_coin,al_mmtype = None,None
 			tn = lbl[-8:] == ':TESTNET'
 			if tn:
-				assert g.proto.is_testnet(),'{} file is testnet but protocol is mainnet!'.format(self.data_desc)
+				assert g.proto.testnet,'{} file is testnet but protocol is mainnet!'.format(self.data_desc)
 				lbl = lbl[:-8]
 			else:
-				assert not g.proto.is_testnet(),'{} file is mainnet but protocol is testnet!'.format(self.data_desc)
+				assert not g.proto.testnet,'{} file is mainnet but protocol is testnet!'.format(self.data_desc)
 			lbl = lbl.split(':',1)
 			if len(lbl) == 2:
 				al_coin,al_mmtype = lbl[0],lbl[1].lower()

+ 1 - 1
mmgen/altcoins/eth/tw.py

@@ -175,7 +175,7 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet):
 			raise TokenNotInWallet('Specified token {!r} not in wallet!'.format(g.token))
 
 		self.token = g.token
-		g.dcoin = self.symbol
+		g.proto.dcoin = self.symbol
 
 	async def is_in_wallet(self,addr):
 		return addr in self.data['tokens'][self.token]

+ 8 - 2
mmgen/globalvars.py

@@ -72,8 +72,6 @@ class GlobalContext:
 
 	# Constant vars - some of these might be overridden in opts.py, but they don't change thereafter
 
-	coin                 = 'BTC'
-	dcoin                = None # the display coin unit
 	token                = ''
 	debug                = False
 	debug_opts           = False
@@ -282,4 +280,12 @@ class GlobalContext:
 			if name[:11] == 'MMGEN_DEBUG':
 				os.environ[name] = '1'
 
+	@property
+	def coin(self):
+		return self.proto.coin
+
+	@property
+	def dcoin(self):
+		return self.proto.dcoin
+
 g = GlobalContext()

+ 4 - 4
mmgen/main_autosign.py

@@ -134,11 +134,11 @@ async def check_daemons_running():
 		coins = ['BTC']
 
 	for coin in coins:
-		g.proto = init_proto(coin,g.testnet)
+		g.proto = init_proto(coin,g.proto.testnet)
 		if g.proto.sign_mode == 'daemon':
 			if g.test_suite:
 				g.proto.daemon_data_dir = 'test/daemons/' + coin.lower()
-				g.rpc_port = CoinDaemon(get_network_id(coin,g.testnet),test_suite=True).rpc_port
+				g.rpc_port = CoinDaemon(get_network_id(coin,g.proto.testnet),test_suite=True).rpc_port
 			vmsg(f'Checking {coin} daemon')
 			try:
 				await rpc_init()
@@ -192,14 +192,14 @@ async def sign_tx_file(txfile,signed_txs):
 
 		g.chain = tmp_tx.chain
 		g.token = tmp_tx.dcoin
-		g.dcoin = tmp_tx.dcoin or g.coin
+		g.proto.dcoin = tmp_tx.dcoin or g.proto.coin
 
 		tx = mmgen.tx.MMGenTxForSigning(txfile)
 
 		if g.proto.sign_mode == 'daemon':
 			if g.test_suite:
 				g.proto.daemon_data_dir = 'test/daemons/' + g.coin.lower()
-				g.rpc_port = CoinDaemon(get_network_id(g.coin,g.testnet),test_suite=True).rpc_port
+				g.rpc_port = CoinDaemon(get_network_id(g.coin,g.proto.testnet),test_suite=True).rpc_port
 			await rpc_init()
 
 		if await txsign(tx,wfs,None,None):

+ 8 - 13
mmgen/opts.py

@@ -267,19 +267,16 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
 			if val != None and hasattr(g,k):
 				setattr(g,k,set_for_type(val,getattr(g,k),'--'+k))
 
-	g.coin = g.coin.upper() # allow user to use lowercase
-	g.dcoin = g.coin # the display coin; for ERC20 tokens, g.dcoin is set to the token symbol
-
-	if g.regtest: # These are equivalent for now
-		g.testnet = True
-
-	g.network = 'regtest' if g.regtest else 'testnet' if g.testnet else 'mainnet'
-
 	from .protocol import init_genonly_altcoins,init_proto
-	altcoin_trust_level = init_genonly_altcoins(g.coin)
 
-	# g.testnet is finalized, so we can set g.proto
-	g.proto = init_proto(g.coin,g.testnet)
+	altcoin_trust_level = init_genonly_altcoins(
+		opt.coin or 'btc',
+		testnet = g.testnet or g.regtest )
+
+	g.proto = init_proto(
+		opt.coin or 'btc',
+		testnet = g.testnet,
+		regtest = g.regtest )
 
 	# this could have been set from long opts
 	if g.daemon_data_dir:
@@ -307,8 +304,6 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
 		opt.quiet = None
 
 	if g.bob or g.alice:
-		g.testnet = True
-		g.regtest = True
 		g.proto = init_proto(g.coin,regtest=True)
 		g.rpc_host = 'localhost'
 		g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob])

+ 24 - 22
mmgen/protocol.py

@@ -71,7 +71,7 @@ finfo = namedtuple('fork_info',['height','hash','name','replayable'])
 
 class CoinProtocol(MMGenObject):
 
-	proto_info = namedtuple('proto_info',['base_name','trust_level']) # trust levels: see altcoin.py
+	proto_info = namedtuple('proto_info',['name','trust_level']) # trust levels: see altcoin.py
 	coins = {
 		'btc': proto_info('Bitcoin',         5),
 		'bch': proto_info('BitcoinCash',     5),
@@ -84,15 +84,16 @@ class CoinProtocol(MMGenObject):
 	core_coins = tuple(coins.keys()) # coins may be added by init_genonly_altcoins(), so save
 
 	class Common(MMGenObject):
+		is_fork_of = None
 		networks = ('mainnet','testnet','regtest')
 
-		def __init__(self,coin,base_name,network):
+		def __init__(self,coin,name,network):
 			self.coin    = coin.upper()
-			self.name    = base_name[0].lower() + base_name[1:]
+			self.dcoin   = self.coin # display coin - for Ethereum, is set to ERC20 token name
+			self.name    = name[0].lower() + name[1:]
 			self.network = network
-
-		def is_testnet(self):
-			return self.network in ('testnet','regtest')
+			self.testnet = network in ('testnet','regtest')
+			self.regtest = network == 'regtest'
 
 		def cap(self,s):
 			return s in self.caps
@@ -243,6 +244,7 @@ class CoinProtocol(MMGenObject):
 		bech32_hrp          = 'bcrt'
 
 	class BitcoinCash(Bitcoin):
+		is_fork_of      = 'bitcoin'
 		# TODO: assumes MSWin user installs in custom dir 'Bitcoin_ABC'
 		daemon_name     = 'bitcoind-abc'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_ABC') if g.platform == 'win' \
@@ -271,6 +273,7 @@ class CoinProtocol(MMGenObject):
 		pass
 
 	class B2X(Bitcoin):
+		is_fork_of      = 'bitcoin'
 		daemon_name     = 'bitcoind-2x'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
 							else os.path.join(g.home_dir,'.bitcoin-2x')
@@ -466,18 +469,18 @@ def init_proto(coin,testnet=False,regtest=False,network=None):
 	if coin not in CoinProtocol.coins:
 		raise ValueError(
 			'{}: not a valid coin for network {}\nSupported coins: {}'.format(
-				coin.upper(),g.network.upper(),
+				coin.upper(),network.upper(),
 				' '.join(c.upper() for c in CoinProtocol.coins) ))
 
-	base_name = CoinProtocol.coins[coin].base_name
-	proto_name = base_name + ('' if network == 'mainnet' else network.capitalize())
+	name = CoinProtocol.coins[coin].name
+	proto_name = name + ('' if network == 'mainnet' else network.capitalize())
 
 	return getattr(CoinProtocol,proto_name)(
-		coin      = coin,
-		base_name = base_name,
-		network   = network )
+		coin    = coin,
+		name    = name,
+		network = network )
 
-def init_genonly_altcoins(usr_coin=None):
+def init_genonly_altcoins(usr_coin=None,testnet=False):
 	"""
 	Initialize altcoin protocol class or classes for current network.
 	If usr_coin is a core coin, initialization is skipped.
@@ -487,7 +490,8 @@ def init_genonly_altcoins(usr_coin=None):
 	"""
 	from .altcoin import CoinInfo as ci
 	data = { 'mainnet': (), 'testnet': () }
-	networks = ['mainnet'] + (['testnet'] if g.testnet else [])
+	networks = ['mainnet'] + (['testnet'] if testnet else [])
+	network = 'testnet' if testnet else 'mainnet'
 
 	if usr_coin == None:
 		for network in networks:
@@ -499,13 +503,13 @@ def init_genonly_altcoins(usr_coin=None):
 		for network in networks:
 			data[network] = (ci.get_entry(usr_coin,network),)
 
-		cinfo = data[g.network][0]
+		cinfo = data[network][0]
 		if not cinfo:
 			m = '{!r}: unrecognized coin for network {}'
-			raise ValueError(m.format(usr_coin.upper(),g.network.upper()))
+			raise ValueError(m.format(usr_coin.upper(),network.upper()))
 		if cinfo.trust_level == -1:
 			m = '{!r}: unsupported (disabled) coin for network {}'
-			raise ValueError(m.format(usr_coin.upper(),g.network.upper()))
+			raise ValueError(m.format(usr_coin.upper(),network.upper()))
 
 		trust_level = cinfo.trust_level
 
@@ -560,9 +564,7 @@ def make_init_genonly_altcoins_str(data):
 	return '\n'.join(gen_text()) + '\n'
 
 def init_coin(coin,testnet=None):
-	if testnet is not None:
-		g.testnet = testnet
-	g.network = 'regtest' if g.regtest else 'testnet' if g.testnet else 'mainnet'
-	g.coin = coin.upper()
-	g.proto = init_proto(g.coin,testnet=g.testnet,regtest=g.regtest)
+	if testnet is None:
+		testnet = g.proto.testnet
+	g.proto = init_proto(coin,testnet=testnet,regtest=g.proto.regtest)
 	return g.proto

+ 15 - 9
mmgen/rpc.py

@@ -25,26 +25,26 @@ from decimal import Decimal
 from .common import *
 from .obj import aInitMeta
 
-rpc_credentials_msg = lambda self: '\n'+fmt(f"""
-	Error: no {self.proto.name.capitalize()} RPC authentication method found
+rpc_credentials_msg = '\n'+fmt("""
+	Error: no {proto_name} RPC authentication method found
 
 	RPC credentials must be supplied using one of the following methods:
 
 	A) If daemon is local and running as same user as you:
 
 	   - no credentials required, or matching rpcuser/rpcpassword and
-	     rpc_user/rpc_password values in {self.proto.name}.conf and mmgen.cfg
+	     rpc_user/rpc_password values in {base_name}.conf and mmgen.cfg
 
 	B) If daemon is running remotely or as different user:
 
-	   - matching credentials in {self.proto.name}.conf and mmgen.cfg as described above
+	   - matching credentials in {base_name}.conf and mmgen.cfg as described above
 
 	The --rpc-user/--rpc-password options may be supplied on the MMGen command line.
 	They override the corresponding values in mmgen.cfg. Set them to an empty string
 	to use cookie authentication with a local server when the options are set
 	in mmgen.cfg.
 
-	For better security, rpcauth should be used in {self.proto.name}.conf instead of
+	For better security, rpcauth should be used in {base_name}.conf instead of
 	rpcuser/rpcpassword.
 
 """,strip_char='\t')
@@ -240,7 +240,10 @@ class RPCClient(MMGenObject):
 				self.auth = auth_data(*cookie.split(':'))
 				return
 
-		die(1,rpc_credentials_msg(self))
+		die(1,rpc_credentials_msg.format(
+			proto_name = capfirst(self.proto.name),
+	        base_name = self.proto.is_fork_of or self.proto.name,
+		))
 
 	# positional params are passed to the daemon, kwargs to the backend
 	# 'timeout' is currently the only supported kwarg
@@ -338,9 +341,12 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
 
 		def check_chaintype_mismatch():
 			try:
-				if g.regtest: assert g.chain == 'regtest','--regtest option selected, but chain is not regtest'
-				if g.testnet: assert g.chain != 'mainnet','--testnet option selected, but chain is mainnet'
-				if not g.testnet: assert g.chain == 'mainnet','mainnet selected, but chain is not mainnet'
+				if g.proto.regtest:
+					assert g.chain == 'regtest', '--regtest option selected, but chain is not regtest'
+				if g.proto.testnet:
+					assert g.chain != 'mainnet', '--testnet option selected, but chain is mainnet'
+				else:
+					assert g.chain == 'mainnet', 'mainnet selected, but chain is not mainnet'
 			except Exception as e:
 				die(1,'{}\nChain is {}!'.format(e.args[0],g.chain))
 

+ 3 - 5
mmgen/tool.py

@@ -1184,10 +1184,8 @@ class tool_api(
 		Valid choices for network: 'mainnet','testnet','regtest'
 		"""
 		from .protocol import init_coin,init_genonly_altcoins
-		altcoin_trust_level = init_genonly_altcoins(coinsym)
+		altcoin_trust_level = init_genonly_altcoins(coinsym,testnet=network in ('testnet','regtest'))
 		warn_altcoins(coinsym,altcoin_trust_level)
-		if network == 'regtest':
-			g.regtest = True
 		return init_coin(coinsym,{'mainnet':False,'testnet':True,'regtest':True}[network])
 
 	@property
@@ -1197,7 +1195,7 @@ class tool_api(
 		from .altcoin import CoinInfo
 		return sorted(set(
 			[c.upper() for c in CoinProtocol.coins]
-			+ [c.symbol for c in CoinInfo.get_supported_coins(g.network)]
+			+ [c.symbol for c in CoinInfo.get_supported_coins(g.proto.network)]
 		))
 
 	@property
@@ -1208,7 +1206,7 @@ class tool_api(
 	@property
 	def network(self):
 		"""The currently configured network"""
-		return g.network
+		return g.proto.network
 
 	@property
 	def addrtypes(self):

+ 2 - 2
mmgen/tx.py

@@ -953,7 +953,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 
 	def create_fn(self):
 		tl = self.get_hex_locktime()
-		tn = ('','.testnet')[g.proto.is_testnet()]
+		tn = ('','.testnet')[g.proto.testnet]
 		self.fn = '{}{}[{!s}{}{}]{x}{}.{}'.format(
 			self.txid,
 			('-'+g.dcoin,'')[g.coin=='BTC'],
@@ -1238,7 +1238,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 
 		if self.dcoin:
 			self.resolve_g_token_from_txfile()
-			g.dcoin = self.dcoin
+			g.proto.dcoin = self.dcoin
 
 	def process_cmd_arg(self,arg,ad_f,ad_w):
 

+ 4 - 5
mmgen/util.py

@@ -821,7 +821,7 @@ def do_license_msg(immed=False):
 # TODO: these belong in protocol.py
 def get_coin_daemon_cfg_fn():
 	# Use dirname() to remove 'bob' or 'alice' component
-	cfg_dir = os.path.dirname(g.data_dir) if g.regtest else g.proto.daemon_data_dir
+	cfg_dir = os.path.dirname(g.data_dir) if g.proto.regtest else g.proto.daemon_data_dir
 	return os.path.join(cfg_dir,g.proto.name+'.conf' )
 
 def get_coin_daemon_cfg_options(req_keys):
@@ -878,10 +878,9 @@ def write_mode(orig_func):
 		return orig_func(self,*args,**kwargs)
 	return f
 
-def get_network_id(coin=None,testnet=None):
-	if coin == None: assert testnet == None
-	if coin != None: assert testnet != None
-	return (coin or g.coin).lower() + ('','_tn')[testnet or g.testnet]
+def get_network_id(coin,testnet):
+	assert type(testnet) == bool
+	return coin.lower() + ('','_tn')[testnet]
 
 def run_session(callback,do_rpc_init=True,proto=None,backend=None):
 	backend = backend or opt.rpc_backend

+ 10 - 10
test/gentest.py

@@ -172,7 +172,7 @@ class GenToolPycoin(GenTool):
 		self.nfnc = network_for_netcode
 
 	def run(self,sec,vcoin):
-		if g.testnet:
+		if g.proto.testnet:
 			vcoin = ci.external_tests['testnet']['pycoin'][vcoin]
 		network = self.nfnc(vcoin)
 		key = network.keys.private(secret_exponent=int(sec,16),is_compressed=addr_type.name != 'legacy')
@@ -212,7 +212,7 @@ class GenToolMoneropy(GenTool):
 def get_tool(arg):
 
 	if arg not in ext_progs + ['ext']:
-		die(1,'{!r}: unsupported tool for network {}'.format(arg,g.network))
+		die(1,'{!r}: unsupported tool for network {}'.format(arg,g.proto.network))
 
 	if opt.all:
 		if arg == 'ext':
@@ -222,7 +222,7 @@ def get_tool(arg):
 		tool = ci.get_test_support(
 			g.coin,
 			addr_type.name,
-			g.network,
+			g.proto.network,
 			verbose = not opt.quiet,
 			tool = arg if arg in ext_progs else None )
 		if not tool:
@@ -251,11 +251,11 @@ def test_equal(desc,a_val,b_val,in_bytes,sec,wif,a_desc,b_desc):
 def gentool_test(kg_a,kg_b,ag,rounds):
 
 	m = "Comparing address generators '{A}' and '{B}' for {N} {c} ({n}), addrtype {a!r}"
-	e = ci.get_entry(g.coin,g.network)
+	e = ci.get_entry(g.coin,g.proto.network)
 	qmsg(green(m.format(
 		A = kg_a.desc,
 		B = kg_b.desc,
-		N = g.network,
+		N = g.proto.network,
 		c = g.coin,
 		n = e.name if e else '---',
 		a = addr_type.name )))
@@ -343,7 +343,7 @@ def dump_test(kg,ag,fh):
 		try:
 			b_sec = PrivKey(wif=b_wif)
 		except:
-			die(2,'\nInvalid {} WIF address in dump file: {}'.format(g.network,b_wif))
+			die(2,'\nInvalid {} WIF address in dump file: {}'.format(g.proto.network,b_wif))
 		a_addr = ag.to_addr(kg.to_pubhex(b_sec))
 		vmsg('\nwif: {}\naddr: {}\n'.format(b_wif,b_addr))
 		tinfo = (bytes.fromhex(b_sec),b_sec,b_wif,kg.desc,fh.name)
@@ -396,7 +396,7 @@ from mmgen.obj import MMGenAddrType,PrivKey
 from mmgen.addr import KeyGenerator,AddrGenerator
 
 addr_type = MMGenAddrType(opt.type or g.proto.dfl_mmtype)
-ext_progs = list(ci.external_tests[g.network])
+ext_progs = list(ci.external_tests[g.proto.network])
 
 arg1 = cmd_args[0].split(':')
 if len(arg1) == 1:
@@ -422,8 +422,8 @@ elif not b and hasattr(arg2,'read'):
 elif a and b and type(arg2) == int:
 	if opt.all:
 		from mmgen.protocol import CoinProtocol,init_genonly_altcoins
-		init_genonly_altcoins()
-		for coin in ci.external_tests[g.network][b.desc]:
+		init_genonly_altcoins(testnet=g.proto.testnet)
+		for coin in ci.external_tests[g.proto.network][b.desc]:
 			if coin.lower() not in CoinProtocol.coins:
 #				ymsg('Coin {} not configured'.format(coin))
 				continue
@@ -433,7 +433,7 @@ elif a and b and type(arg2) == int:
 			# g.proto has changed, so reinit kg and ag just to be on the safe side:
 			a = KeyGenerator(addr_type,a_num)
 			ag = AddrGenerator(addr_type)
-			b_chk = ci.get_test_support(g.coin,addr_type.name,g.network,tool=b.desc,verbose=not opt.quiet)
+			b_chk = ci.get_test_support(g.coin,addr_type.name,g.proto.network,tool=b.desc,verbose=not opt.quiet)
 			if b_chk == b.desc:
 				gentool_test(a,b,ag,arg2)
 	else:

+ 2 - 2
test/objattrtest.py

@@ -147,9 +147,9 @@ def test_object(test_data,objname):
 
 def do_loop():
 	import importlib
-	modname = 'test.objattrtest_py_d.oat_{}_{}'.format(g.coin.lower(),g.network)
+	modname = 'test.objattrtest_py_d.oat_{}_{}'.format(g.coin.lower(),g.proto.network)
 	test_data = importlib.import_module(modname).tests
-	gmsg('Running immutable attribute tests for {} {}'.format(g.coin,g.network))
+	gmsg('Running immutable attribute tests for {} {}'.format(g.coin,g.proto.network))
 
 	utests = cmd_args
 	for obj in test_data:

+ 2 - 2
test/objtest.py

@@ -119,9 +119,9 @@ def run_test(test,arg,input_data):
 
 def do_loop():
 	import importlib
-	modname = 'test.objtest_py_d.ot_{}_{}'.format(g.coin.lower(),g.network)
+	modname = 'test.objtest_py_d.ot_{}_{}'.format(g.coin.lower(),g.proto.network)
 	test_data = importlib.import_module(modname).tests
-	gmsg('Running data object tests for {} {}'.format(g.coin,g.network))
+	gmsg('Running data object tests for {} {}'.format(g.coin,g.proto.network))
 
 	clr = None
 	utests = cmd_args

+ 2 - 2
test/test.py

@@ -697,7 +697,7 @@ class TestSuiteRunner(object):
 			segwit_opt = None
 
 		m1 = ('test group {g!r}','{g}:{c}')[bool(cmd)].format(g=gname,c=cmd)
-		m2 = ' for {} {}net'.format(g.coin.lower(),'test' if g.testnet else 'main') \
+		m2 = ' for {} {}net'.format(g.coin.lower(),'test' if g.proto.testnet else 'main') \
 				if len(ts_cls.networks) != 1 else ''
 		m3 = ' (--{})'.format(segwit_opt.replace('_','-')) if segwit_opt else ''
 		m = m1 + m2 + m3
@@ -710,7 +710,7 @@ class TestSuiteRunner(object):
 		nws = [(e.split('_')[0],'testnet') if '_' in e else (e,'mainnet') for e in ts_cls.networks]
 		if nws:
 			coin = g.coin.lower()
-			nw = ('mainnet','testnet')[g.testnet]
+			nw = ('mainnet','testnet')[g.proto.testnet]
 			for a,b in nws:
 				if a == coin and b == nw:
 					break

+ 1 - 1
test/test_py_d/ts_base.py

@@ -42,7 +42,7 @@ class TestSuiteBase(object):
 		self.usr_rand_chars = (5,30)[bool(opt.usr_random)]
 		self.usr_rand_arg = '-r{}'.format(self.usr_rand_chars)
 		self.altcoin_pfx = '' if g.proto.base_coin == 'BTC' else '-'+g.proto.base_coin
-		self.tn_ext = ('','.testnet')[g.testnet]
+		self.tn_ext = ('','.testnet')[g.proto.testnet]
 		d = {'bch':'btc','btc':'btc','ltc':'ltc'}
 		self.fork = d[g.coin.lower()] if g.coin.lower() in d else None
 

+ 2 - 1
test/test_py_d/ts_main.py

@@ -147,7 +147,8 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
 		if g.coin.lower() not in self.networks:
 			return
 		from mmgen.rpc import rpc_init
-		g.regtest = False # rpc_init hack
+		if g.proto.regtest: # rpc_init hack
+			g.proto = init_proto(g.coin,network='testnet')
 		self.rpc = run_session(rpc_init())
 		self.lbl_id = ('account','label')['label_api' in self.rpc.caps]
 		if g.coin in ('BTC','BCH','LTC'):

+ 2 - 2
test/test_py_d/ts_ref.py

@@ -31,7 +31,7 @@ from .ts_base import *
 from .ts_shared import *
 
 wpasswd = 'reference password'
-nw_name = '{} {}'.format(g.coin,('Mainnet','Testnet')[g.testnet])
+nw_name = '{} {}'.format(g.coin,('Mainnet','Testnet')[g.proto.testnet])
 
 class TestSuiteRef(TestSuiteBase,TestSuiteShared):
 	'saved reference address, password and transaction files'
@@ -220,7 +220,7 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared):
 			t.do_decrypt_ka_data(hp=ref_kafile_hash_preset,pw=ref_kafile_pass,have_yes_opt=True)
 		chksum_key = '_'.join([af_key,'chksum'] + ([coin.lower()] if coin else []) + ([mmtype] if mmtype else []))
 		rc = self.chk_data[chksum_key]
-		ref_chksum = rc if (ftype == 'passwd' or coin) else rc[g.proto.base_coin.lower()][g.testnet]
+		ref_chksum = rc if (ftype == 'passwd' or coin) else rc[g.proto.base_coin.lower()][g.proto.testnet]
 		if pat:
 			t.expect(pat,regex=True)
 		t.expect(chksum_pat,regex=True)

+ 2 - 4
test/test_py_d/ts_ref_altcoin.py

@@ -89,7 +89,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
 			coin,token = ('eth','mm1') if k == 'mm1' else (k,None)
 			ref_subdir = self._get_ref_subdir_by_coin(coin)
 			for tn in (False,True):
-				extra_opts = ['--coin='+coin,'--testnet='+('0','1')[tn]]
+				extra_opts = ['--coin='+coin,f'--testnet={int(tn)}']
 				if tn and coin == 'etc':
 					continue
 				if coin == 'bch':
@@ -98,8 +98,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
 					extra_opts += [
 						'--daemon-data-dir=test/daemons/bch',
 						'--rpc-port={}'.format(CoinDaemon(network_id,test_suite=True).rpc_port) ]
-				g.testnet = tn
-				init_coin(coin)
+				init_coin(coin,testnet=tn)
 				fn = TestSuiteRef.sources['ref_tx_file'][token or coin][bool(tn)]
 				tf = joinpath(ref_dir,ref_subdir,fn)
 				wf = dfl_words_file
@@ -113,7 +112,6 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
 				if coin == 'bch':
 					stop_test_daemons(network_id)
 				ok_msg()
-		g.testnet = False
 		init_coin('btc')
 		t.skip_ok = True
 		return t

+ 1 - 2
test/test_py_d/ts_regtest.py

@@ -244,7 +244,6 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 	usr_subsids = { 'bob': {}, 'alice': {} }
 
 	def __init__(self,trunner,cfgs,spawn):
-		g.regtest = True
 		os.environ['MMGEN_TEST_SUITE_REGTEST'] = '1'
 		from mmgen.regtest import MMGenRegtest
 		rt = MMGenRegtest(g.coin)
@@ -268,7 +267,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 
 	def setup(self):
 		os.environ['MMGEN_BOGUS_WALLET_DATA'] = ''
-		if g.testnet:
+		if g.proto.testnet:
 			die(2,'--testnet option incompatible with regtest test suite')
 		try: shutil.rmtree(joinpath(self.tr.data_dir,'regtest'))
 		except: pass

+ 2 - 2
test/test_py_d/ts_shared.py

@@ -225,7 +225,7 @@ class TestSuiteShared(object):
 		t.read() if stdout else t.written_to_file(('Addresses','Password list')[passgen])
 		if check_ref:
 			chk_ref = (self.chk_data[self.test_name] if passgen else
-						self.chk_data[self.test_name][self.fork][g.testnet])
+						self.chk_data[self.test_name][self.fork][g.proto.testnet])
 			cmp_or_die(chk,chk_ref,desc='{}list data checksum'.format(ftype))
 		return t
 
@@ -241,7 +241,7 @@ class TestSuiteShared(object):
 		t.passphrase(wcls.desc,self.wpasswd)
 		chk = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True)
 		if check_ref:
-			chk_ref = self.chk_data[self.test_name][self.fork][g.testnet]
+			chk_ref = self.chk_data[self.test_name][self.fork][g.proto.testnet]
 			cmp_or_die(chk,chk_ref,desc='key-address list data checksum')
 		t.expect('Encrypt key list? (y/N): ','y')
 		t.usr_rand(self.usr_rand_chars)

+ 1 - 1
test/test_py_d/ts_wallet.py

@@ -48,7 +48,7 @@ class TestSuiteWalletConv(TestSuiteBase,TestSuiteShared):
 					'hic_wallet_old':  '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
 				},
 				'256': {
-					'ref_wallet':      '98831F3A-{}[256,1].mmdat'.format(('27F2BF93','E2687906')[g.testnet]),
+					'ref_wallet':      '98831F3A-{}[256,1].mmdat'.format(('27F2BF93','E2687906')[g.proto.testnet]),
 					'ic_wallet':       '98831F3A-5482381C-18460FB1[256,1].mmincog',
 					'ic_wallet_hex':   '98831F3A-1630A9F2-870376A9[256,1].mmincox',
 

+ 1 - 1
test/tooltest.py

@@ -119,7 +119,7 @@ cfg = {
 
 ref_subdir  = '' if g.proto.base_coin == 'BTC' else g.proto.name
 altcoin_pfx = '' if g.proto.base_coin == 'BTC' else '-'+g.proto.base_coin
-tn_ext = ('','.testnet')[g.testnet]
+tn_ext = ('','.testnet')[g.proto.testnet]
 
 mmgen_cmd = 'mmgen-tool'
 

+ 4 - 3
test/tooltest2.py

@@ -774,9 +774,9 @@ coin_dependent_groups = ('Coin','File') # TODO: do this as attr of each group in
 
 def run_test(gid,cmd_name):
 	data = tests[gid][cmd_name]
-	# behavior is like test.py: run coin-dependent tests only if g.testnet or g.coin != BTC
+	# behavior is like test.py: run coin-dependent tests only if g.proto.testnet or g.coin != BTC
 	if gid in coin_dependent_groups:
-		k = '{}_{}net'.format((g.token.lower() if g.token else g.coin.lower()),('main','test')[g.testnet])
+		k = '{}_{}net'.format((g.token.lower() if g.token else g.coin.lower()),('main','test')[g.proto.testnet])
 		if k in data:
 			data = data[k]
 			m2 = ' ({})'.format(k)
@@ -784,7 +784,8 @@ def run_test(gid,cmd_name):
 			qmsg("-- no data for {} ({}) - skipping".format(cmd_name,k))
 			return
 	else:
-		if g.coin != 'BTC' or g.testnet: return
+		if g.coin != 'BTC' or g.proto.testnet:
+			return
 		m2 = ''
 	m = '{} {}{}'.format(purple('Testing'), cmd_name if opt.names else docstring_head(tc[cmd_name]),m2)