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):
 	def scramble_seed(self,seed):
 		is_btcfork = g.proto.base_coin == 'BTC'
 		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)')
 			dmsg_sc('str','(none)')
 			return seed
 			return seed
 		if g.proto.base_coin == 'ETH':
 		if g.proto.base_coin == 'ETH':
@@ -495,7 +495,7 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 		else:
 		else:
 			scramble_key = (g.coin.lower()+':','')[is_btcfork] + self.al_id.mmtype.name
 			scramble_key = (g.coin.lower()+':','')[is_btcfork] + self.al_id.mmtype.name
 		from .crypto import scramble_seed
 		from .crypto import scramble_seed
-		if g.proto.is_testnet():
+		if g.proto.testnet:
 			scramble_key += ':testnet'
 			scramble_key += ':testnet'
 		dmsg_sc('str',scramble_key)
 		dmsg_sc('str',scramble_key)
 		return scramble_seed(seed,scramble_key.encode())
 		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
 		self.ext += '.'+g.mmenc_ext
 
 
 	def write_to_file(self,ask_tty=True,ask_write_default_yes=False,binary=False,desc=None):
 	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 '')
 		fn = '{}{x}{}.{}'.format(self.id_str,tn,self.ext,x='-α' if g.debug_utf8 else '')
 		ask_tty = self.has_keys and not opt.quiet
 		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)
 		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):
 	def make_label(self):
 		bc,mt = g.proto.base_coin,self.al_id.mmtype
 		bc,mt = g.proto.base_coin,self.al_id.mmtype
 		l_coin = [] if bc == 'BTC' else [g.coin] if bc == 'ETH' else [bc]
 		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)
 		lbl_p2 = ':'.join(l_coin+l_type+l_tn)
 		return self.al_id.sid + ('',' ')[bool(lbl_p2)] + lbl_p2
 		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
 			al_coin,al_mmtype = None,None
 			tn = lbl[-8:] == ':TESTNET'
 			tn = lbl[-8:] == ':TESTNET'
 			if tn:
 			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]
 				lbl = lbl[:-8]
 			else:
 			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)
 			lbl = lbl.split(':',1)
 			if len(lbl) == 2:
 			if len(lbl) == 2:
 				al_coin,al_mmtype = lbl[0],lbl[1].lower()
 				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))
 			raise TokenNotInWallet('Specified token {!r} not in wallet!'.format(g.token))
 
 
 		self.token = g.token
 		self.token = g.token
-		g.dcoin = self.symbol
+		g.proto.dcoin = self.symbol
 
 
 	async def is_in_wallet(self,addr):
 	async def is_in_wallet(self,addr):
 		return addr in self.data['tokens'][self.token]
 		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
 	# 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                = ''
 	token                = ''
 	debug                = False
 	debug                = False
 	debug_opts           = False
 	debug_opts           = False
@@ -282,4 +280,12 @@ class GlobalContext:
 			if name[:11] == 'MMGEN_DEBUG':
 			if name[:11] == 'MMGEN_DEBUG':
 				os.environ[name] = '1'
 				os.environ[name] = '1'
 
 
+	@property
+	def coin(self):
+		return self.proto.coin
+
+	@property
+	def dcoin(self):
+		return self.proto.dcoin
+
 g = GlobalContext()
 g = GlobalContext()

+ 4 - 4
mmgen/main_autosign.py

@@ -134,11 +134,11 @@ async def check_daemons_running():
 		coins = ['BTC']
 		coins = ['BTC']
 
 
 	for coin in coins:
 	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.proto.sign_mode == 'daemon':
 			if g.test_suite:
 			if g.test_suite:
 				g.proto.daemon_data_dir = 'test/daemons/' + coin.lower()
 				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')
 			vmsg(f'Checking {coin} daemon')
 			try:
 			try:
 				await rpc_init()
 				await rpc_init()
@@ -192,14 +192,14 @@ async def sign_tx_file(txfile,signed_txs):
 
 
 		g.chain = tmp_tx.chain
 		g.chain = tmp_tx.chain
 		g.token = tmp_tx.dcoin
 		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)
 		tx = mmgen.tx.MMGenTxForSigning(txfile)
 
 
 		if g.proto.sign_mode == 'daemon':
 		if g.proto.sign_mode == 'daemon':
 			if g.test_suite:
 			if g.test_suite:
 				g.proto.daemon_data_dir = 'test/daemons/' + g.coin.lower()
 				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()
 			await rpc_init()
 
 
 		if await txsign(tx,wfs,None,None):
 		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):
 			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))
 
 
-	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
 	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
 	# this could have been set from long opts
 	if g.daemon_data_dir:
 	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
 		opt.quiet = None
 
 
 	if g.bob or g.alice:
 	if g.bob or g.alice:
-		g.testnet = True
-		g.regtest = True
 		g.proto = init_proto(g.coin,regtest=True)
 		g.proto = init_proto(g.coin,regtest=True)
 		g.rpc_host = 'localhost'
 		g.rpc_host = 'localhost'
 		g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob])
 		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):
 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 = {
 	coins = {
 		'btc': proto_info('Bitcoin',         5),
 		'btc': proto_info('Bitcoin',         5),
 		'bch': proto_info('BitcoinCash',     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
 	core_coins = tuple(coins.keys()) # coins may be added by init_genonly_altcoins(), so save
 
 
 	class Common(MMGenObject):
 	class Common(MMGenObject):
+		is_fork_of = None
 		networks = ('mainnet','testnet','regtest')
 		networks = ('mainnet','testnet','regtest')
 
 
-		def __init__(self,coin,base_name,network):
+		def __init__(self,coin,name,network):
 			self.coin    = coin.upper()
 			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
 			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):
 		def cap(self,s):
 			return s in self.caps
 			return s in self.caps
@@ -243,6 +244,7 @@ class CoinProtocol(MMGenObject):
 		bech32_hrp          = 'bcrt'
 		bech32_hrp          = 'bcrt'
 
 
 	class BitcoinCash(Bitcoin):
 	class BitcoinCash(Bitcoin):
+		is_fork_of      = 'bitcoin'
 		# TODO: assumes MSWin user installs in custom dir 'Bitcoin_ABC'
 		# TODO: assumes MSWin user installs in custom dir 'Bitcoin_ABC'
 		daemon_name     = 'bitcoind-abc'
 		daemon_name     = 'bitcoind-abc'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_ABC') if g.platform == 'win' \
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_ABC') if g.platform == 'win' \
@@ -271,6 +273,7 @@ class CoinProtocol(MMGenObject):
 		pass
 		pass
 
 
 	class B2X(Bitcoin):
 	class B2X(Bitcoin):
+		is_fork_of      = 'bitcoin'
 		daemon_name     = 'bitcoind-2x'
 		daemon_name     = 'bitcoind-2x'
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
 		daemon_data_dir = os.path.join(os.getenv('APPDATA'),'Bitcoin_2X') if g.platform == 'win' \
 							else os.path.join(g.home_dir,'.bitcoin-2x')
 							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:
 	if coin not in CoinProtocol.coins:
 		raise ValueError(
 		raise ValueError(
 			'{}: not a valid coin for network {}\nSupported coins: {}'.format(
 			'{}: 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) ))
 				' '.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)(
 	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.
 	Initialize altcoin protocol class or classes for current network.
 	If usr_coin is a core coin, initialization is skipped.
 	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
 	from .altcoin import CoinInfo as ci
 	data = { 'mainnet': (), 'testnet': () }
 	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:
 	if usr_coin == None:
 		for network in networks:
 		for network in networks:
@@ -499,13 +503,13 @@ def init_genonly_altcoins(usr_coin=None):
 		for network in networks:
 		for network in networks:
 			data[network] = (ci.get_entry(usr_coin,network),)
 			data[network] = (ci.get_entry(usr_coin,network),)
 
 
-		cinfo = data[g.network][0]
+		cinfo = data[network][0]
 		if not cinfo:
 		if not cinfo:
 			m = '{!r}: unrecognized coin for network {}'
 			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:
 		if cinfo.trust_level == -1:
 			m = '{!r}: unsupported (disabled) coin for network {}'
 			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
 		trust_level = cinfo.trust_level
 
 
@@ -560,9 +564,7 @@ def make_init_genonly_altcoins_str(data):
 	return '\n'.join(gen_text()) + '\n'
 	return '\n'.join(gen_text()) + '\n'
 
 
 def init_coin(coin,testnet=None):
 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
 	return g.proto

+ 15 - 9
mmgen/rpc.py

@@ -25,26 +25,26 @@ from decimal import Decimal
 from .common import *
 from .common import *
 from .obj import aInitMeta
 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:
 	RPC credentials must be supplied using one of the following methods:
 
 
 	A) If daemon is local and running as same user as you:
 	A) If daemon is local and running as same user as you:
 
 
 	   - no credentials required, or matching rpcuser/rpcpassword and
 	   - 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:
 	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.
 	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
 	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
 	to use cookie authentication with a local server when the options are set
 	in mmgen.cfg.
 	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.
 	rpcuser/rpcpassword.
 
 
 """,strip_char='\t')
 """,strip_char='\t')
@@ -240,7 +240,10 @@ class RPCClient(MMGenObject):
 				self.auth = auth_data(*cookie.split(':'))
 				self.auth = auth_data(*cookie.split(':'))
 				return
 				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
 	# positional params are passed to the daemon, kwargs to the backend
 	# 'timeout' is currently the only supported kwarg
 	# 'timeout' is currently the only supported kwarg
@@ -338,9 +341,12 @@ class BitcoinRPCClient(RPCClient,metaclass=aInitMeta):
 
 
 		def check_chaintype_mismatch():
 		def check_chaintype_mismatch():
 			try:
 			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:
 			except Exception as e:
 				die(1,'{}\nChain is {}!'.format(e.args[0],g.chain))
 				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'
 		Valid choices for network: 'mainnet','testnet','regtest'
 		"""
 		"""
 		from .protocol import init_coin,init_genonly_altcoins
 		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)
 		warn_altcoins(coinsym,altcoin_trust_level)
-		if network == 'regtest':
-			g.regtest = True
 		return init_coin(coinsym,{'mainnet':False,'testnet':True,'regtest':True}[network])
 		return init_coin(coinsym,{'mainnet':False,'testnet':True,'regtest':True}[network])
 
 
 	@property
 	@property
@@ -1197,7 +1195,7 @@ class tool_api(
 		from .altcoin import CoinInfo
 		from .altcoin import CoinInfo
 		return sorted(set(
 		return sorted(set(
 			[c.upper() for c in CoinProtocol.coins]
 			[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
 	@property
@@ -1208,7 +1206,7 @@ class tool_api(
 	@property
 	@property
 	def network(self):
 	def network(self):
 		"""The currently configured network"""
 		"""The currently configured network"""
-		return g.network
+		return g.proto.network
 
 
 	@property
 	@property
 	def addrtypes(self):
 	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):
 	def create_fn(self):
 		tl = self.get_hex_locktime()
 		tl = self.get_hex_locktime()
-		tn = ('','.testnet')[g.proto.is_testnet()]
+		tn = ('','.testnet')[g.proto.testnet]
 		self.fn = '{}{}[{!s}{}{}]{x}{}.{}'.format(
 		self.fn = '{}{}[{!s}{}{}]{x}{}.{}'.format(
 			self.txid,
 			self.txid,
 			('-'+g.dcoin,'')[g.coin=='BTC'],
 			('-'+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:
 		if self.dcoin:
 			self.resolve_g_token_from_txfile()
 			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):
 	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
 # TODO: these belong in protocol.py
 def get_coin_daemon_cfg_fn():
 def get_coin_daemon_cfg_fn():
 	# Use dirname() to remove 'bob' or 'alice' component
 	# 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' )
 	return os.path.join(cfg_dir,g.proto.name+'.conf' )
 
 
 def get_coin_daemon_cfg_options(req_keys):
 def get_coin_daemon_cfg_options(req_keys):
@@ -878,10 +878,9 @@ def write_mode(orig_func):
 		return orig_func(self,*args,**kwargs)
 		return orig_func(self,*args,**kwargs)
 	return f
 	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):
 def run_session(callback,do_rpc_init=True,proto=None,backend=None):
 	backend = backend or opt.rpc_backend
 	backend = backend or opt.rpc_backend

+ 10 - 10
test/gentest.py

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

+ 2 - 2
test/objattrtest.py

@@ -147,9 +147,9 @@ def test_object(test_data,objname):
 
 
 def do_loop():
 def do_loop():
 	import importlib
 	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
 	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
 	utests = cmd_args
 	for obj in test_data:
 	for obj in test_data:

+ 2 - 2
test/objtest.py

@@ -119,9 +119,9 @@ def run_test(test,arg,input_data):
 
 
 def do_loop():
 def do_loop():
 	import importlib
 	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
 	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
 	clr = None
 	utests = cmd_args
 	utests = cmd_args

+ 2 - 2
test/test.py

@@ -697,7 +697,7 @@ class TestSuiteRunner(object):
 			segwit_opt = None
 			segwit_opt = None
 
 
 		m1 = ('test group {g!r}','{g}:{c}')[bool(cmd)].format(g=gname,c=cmd)
 		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 ''
 				if len(ts_cls.networks) != 1 else ''
 		m3 = ' (--{})'.format(segwit_opt.replace('_','-')) if segwit_opt else ''
 		m3 = ' (--{})'.format(segwit_opt.replace('_','-')) if segwit_opt else ''
 		m = m1 + m2 + m3
 		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]
 		nws = [(e.split('_')[0],'testnet') if '_' in e else (e,'mainnet') for e in ts_cls.networks]
 		if nws:
 		if nws:
 			coin = g.coin.lower()
 			coin = g.coin.lower()
-			nw = ('mainnet','testnet')[g.testnet]
+			nw = ('mainnet','testnet')[g.proto.testnet]
 			for a,b in nws:
 			for a,b in nws:
 				if a == coin and b == nw:
 				if a == coin and b == nw:
 					break
 					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_chars = (5,30)[bool(opt.usr_random)]
 		self.usr_rand_arg = '-r{}'.format(self.usr_rand_chars)
 		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.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'}
 		d = {'bch':'btc','btc':'btc','ltc':'ltc'}
 		self.fork = d[g.coin.lower()] if g.coin.lower() in d else None
 		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:
 		if g.coin.lower() not in self.networks:
 			return
 			return
 		from mmgen.rpc import rpc_init
 		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.rpc = run_session(rpc_init())
 		self.lbl_id = ('account','label')['label_api' in self.rpc.caps]
 		self.lbl_id = ('account','label')['label_api' in self.rpc.caps]
 		if g.coin in ('BTC','BCH','LTC'):
 		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 *
 from .ts_shared import *
 
 
 wpasswd = 'reference password'
 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):
 class TestSuiteRef(TestSuiteBase,TestSuiteShared):
 	'saved reference address, password and transaction files'
 	'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)
 			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 []))
 		chksum_key = '_'.join([af_key,'chksum'] + ([coin.lower()] if coin else []) + ([mmtype] if mmtype else []))
 		rc = self.chk_data[chksum_key]
 		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:
 		if pat:
 			t.expect(pat,regex=True)
 			t.expect(pat,regex=True)
 		t.expect(chksum_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)
 			coin,token = ('eth','mm1') if k == 'mm1' else (k,None)
 			ref_subdir = self._get_ref_subdir_by_coin(coin)
 			ref_subdir = self._get_ref_subdir_by_coin(coin)
 			for tn in (False,True):
 			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':
 				if tn and coin == 'etc':
 					continue
 					continue
 				if coin == 'bch':
 				if coin == 'bch':
@@ -98,8 +98,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
 					extra_opts += [
 					extra_opts += [
 						'--daemon-data-dir=test/daemons/bch',
 						'--daemon-data-dir=test/daemons/bch',
 						'--rpc-port={}'.format(CoinDaemon(network_id,test_suite=True).rpc_port) ]
 						'--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)]
 				fn = TestSuiteRef.sources['ref_tx_file'][token or coin][bool(tn)]
 				tf = joinpath(ref_dir,ref_subdir,fn)
 				tf = joinpath(ref_dir,ref_subdir,fn)
 				wf = dfl_words_file
 				wf = dfl_words_file
@@ -113,7 +112,6 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase):
 				if coin == 'bch':
 				if coin == 'bch':
 					stop_test_daemons(network_id)
 					stop_test_daemons(network_id)
 				ok_msg()
 				ok_msg()
-		g.testnet = False
 		init_coin('btc')
 		init_coin('btc')
 		t.skip_ok = True
 		t.skip_ok = True
 		return t
 		return t

+ 1 - 2
test/test_py_d/ts_regtest.py

@@ -244,7 +244,6 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 	usr_subsids = { 'bob': {}, 'alice': {} }
 	usr_subsids = { 'bob': {}, 'alice': {} }
 
 
 	def __init__(self,trunner,cfgs,spawn):
 	def __init__(self,trunner,cfgs,spawn):
-		g.regtest = True
 		os.environ['MMGEN_TEST_SUITE_REGTEST'] = '1'
 		os.environ['MMGEN_TEST_SUITE_REGTEST'] = '1'
 		from mmgen.regtest import MMGenRegtest
 		from mmgen.regtest import MMGenRegtest
 		rt = MMGenRegtest(g.coin)
 		rt = MMGenRegtest(g.coin)
@@ -268,7 +267,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 
 
 	def setup(self):
 	def setup(self):
 		os.environ['MMGEN_BOGUS_WALLET_DATA'] = ''
 		os.environ['MMGEN_BOGUS_WALLET_DATA'] = ''
-		if g.testnet:
+		if g.proto.testnet:
 			die(2,'--testnet option incompatible with regtest test suite')
 			die(2,'--testnet option incompatible with regtest test suite')
 		try: shutil.rmtree(joinpath(self.tr.data_dir,'regtest'))
 		try: shutil.rmtree(joinpath(self.tr.data_dir,'regtest'))
 		except: pass
 		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])
 		t.read() if stdout else t.written_to_file(('Addresses','Password list')[passgen])
 		if check_ref:
 		if check_ref:
 			chk_ref = (self.chk_data[self.test_name] if passgen else
 			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))
 			cmp_or_die(chk,chk_ref,desc='{}list data checksum'.format(ftype))
 		return t
 		return t
 
 
@@ -241,7 +241,7 @@ class TestSuiteShared(object):
 		t.passphrase(wcls.desc,self.wpasswd)
 		t.passphrase(wcls.desc,self.wpasswd)
 		chk = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True)
 		chk = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True)
 		if check_ref:
 		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')
 			cmp_or_die(chk,chk_ref,desc='key-address list data checksum')
 		t.expect('Encrypt key list? (y/N): ','y')
 		t.expect('Encrypt key list? (y/N): ','y')
 		t.usr_rand(self.usr_rand_chars)
 		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',
 					'hic_wallet_old':  '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
 				},
 				},
 				'256': {
 				'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':       '98831F3A-5482381C-18460FB1[256,1].mmincog',
 					'ic_wallet_hex':   '98831F3A-1630A9F2-870376A9[256,1].mmincox',
 					'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
 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
 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'
 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):
 def run_test(gid,cmd_name):
 	data = tests[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:
 	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:
 		if k in data:
 			data = data[k]
 			data = data[k]
 			m2 = ' ({})'.format(k)
 			m2 = ' ({})'.format(k)
@@ -784,7 +784,8 @@ def run_test(gid,cmd_name):
 			qmsg("-- no data for {} ({}) - skipping".format(cmd_name,k))
 			qmsg("-- no data for {} ({}) - skipping".format(cmd_name,k))
 			return
 			return
 	else:
 	else:
-		if g.coin != 'BTC' or g.testnet: return
+		if g.coin != 'BTC' or g.proto.testnet:
+			return
 		m2 = ''
 		m2 = ''
 	m = '{} {}{}'.format(purple('Testing'), cmd_name if opt.names else docstring_head(tc[cmd_name]),m2)
 	m = '{} {}{}'.format(purple('Testing'), cmd_name if opt.names else docstring_head(tc[cmd_name]),m2)