Browse Source

protocol.py: new init_proto() factory function

The MMGen Project 4 years ago
parent
commit
8a4fbab48d
10 changed files with 54 additions and 52 deletions
  1. 2 2
      mmgen/addr.py
  2. 2 2
      mmgen/altcoin.py
  3. 2 2
      mmgen/daemon.py
  4. 2 2
      mmgen/main_autosign.py
  5. 6 6
      mmgen/opts.py
  6. 29 30
      mmgen/protocol.py
  7. 2 2
      mmgen/regtest.py
  8. 4 1
      mmgen/tool.py
  9. 1 1
      test/gentest.py
  10. 4 4
      test/test_py_d/ts_regtest.py

+ 2 - 2
mmgen/addr.py

@@ -697,8 +697,8 @@ Removed {{}} duplicate WIF key{{}} from keylist (also in {pnm} key-address file
 			else:
 				mmtype = MMGenAddrType(al_mmtype,on_fail='raise')
 
-			from .protocol import CoinProtocol
-			base_coin = CoinProtocol(al_coin or 'BTC',testnet=False).base_coin
+			from .protocol import init_proto
+			base_coin = init_proto(al_coin or 'BTC',testnet=False).base_coin
 			return base_coin,mmtype,tn
 
 		def check_coin_mismatch(base_coin): # die if addrfile coin doesn't match g.coin

+ 2 - 2
mmgen/altcoin.py

@@ -428,13 +428,13 @@ class CoinInfo(object):
 
 	@classmethod
 	def verify_core_coin_data(cls,quiet=False,verbose=False):
-		from mmgen.protocol import CoinProtocol
+		from mmgen.protocol import CoinProtocol,init_proto
 
 		for network in ('mainnet','testnet'):
 			for coin in CoinProtocol.core_coins:
 				e = cls.get_entry(coin,network)
 				if e:
-					proto = CoinProtocol(coin,testnet=network=='testnet')
+					proto = init_proto(coin,testnet=network=='testnet')
 					cdata = (network,coin,e,type(proto).__name__,verbose)
 					if not quiet:
 						msg('Verifying {} {}'.format(coin.upper(),network))

+ 2 - 2
mmgen/daemon.py

@@ -353,8 +353,8 @@ class CoinDaemon(Daemon):
 			me.desc = 'test suite daemon'
 			rel_datadir = os.path.join('test','daemons',daemon_id)
 		else:
-			from .protocol import CoinProtocol
-			me.datadir = CoinProtocol(daemon_id,False).daemon_data_dir
+			from .protocol import init_proto
+			me.datadir = init_proto(daemon_id,False).daemon_data_dir
 
 		if test_suite:
 			me.datadir = os.path.abspath(os.path.join(os.getcwd(),rel_datadir))

+ 2 - 2
mmgen/main_autosign.py

@@ -113,7 +113,7 @@ exit_if_mswin('autosigning')
 
 import mmgen.tx
 from .txsign import txsign
-from .protocol import CoinProtocol,init_coin
+from .protocol import init_proto,init_coin
 from .rpc import rpc_init
 
 if g.test_suite:
@@ -134,7 +134,7 @@ async def check_daemons_running():
 		coins = ['BTC']
 
 	for coin in coins:
-		g.proto = CoinProtocol(coin,g.testnet)
+		g.proto = init_proto(coin,g.testnet)
 		if g.proto.sign_mode == 'daemon':
 			if g.test_suite:
 				g.proto.daemon_data_dir = 'test/daemons/' + coin.lower()

+ 6 - 6
mmgen/opts.py

@@ -87,14 +87,14 @@ def init_term_and_color():
 		init_color(num_colors=('auto',256)[bool(g.force_256_color)])
 
 def override_globals_from_cfg_file(ucfg):
-	from .protocol import CoinProtocol
+	from .protocol import CoinProtocol,init_proto
 	for d in ucfg.parse():
 		val = d.value
 		if d.name in g.cfg_file_opts:
 			ns = d.name.split('_')
 			if ns[0] in CoinProtocol.coins:
 				nse,tn = (ns[2:],True) if len(ns) > 2 and ns[1] == 'testnet' else (ns[1:],False)
-				cls = CoinProtocol(ns[0],tn)
+				cls = init_proto(ns[0],tn)
 				attr = '_'.join(nse)
 			else:
 				cls = g
@@ -259,11 +259,11 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
 
 	g.network = 'testnet' if g.testnet else 'mainnet'
 
-	from .protocol import init_genonly_altcoins,CoinProtocol
+	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 = CoinProtocol(g.coin,g.testnet)
+	g.proto = init_proto(g.coin,g.testnet)
 
 	# this could have been set from long opts
 	if g.daemon_data_dir:
@@ -293,7 +293,7 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
 	if g.bob or g.alice:
 		g.testnet = True
 		g.regtest = True
-		g.proto = CoinProtocol(g.coin,g.testnet)
+		g.proto = init_proto(g.coin,g.testnet)
 		g.rpc_host = 'localhost'
 		g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob])
 		from .regtest import MMGenRegtest
@@ -491,7 +491,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
 
 	def chk_coin(key,val,desc):
 		from .protocol import CoinProtocol
-		opt_is_in_list(val.lower(),list(CoinProtocol.coins.keys()),'coin')
+		opt_is_in_list(val.lower(),CoinProtocol.coins,'coin')
 
 	def chk_rbf(key,val,desc):
 		if not g.proto.cap('rbf'):

+ 29 - 30
mmgen/protocol.py

@@ -69,6 +69,19 @@ def _b58chk_decode(s):
 
 finfo = namedtuple('fork_info',['height','hash','name','replayable'])
 
+class CoinProtocol(MMGenObject):
+	proto_info = namedtuple('proto_info',['mainnet','testnet','trust_level']) # trust levels: see altcoin.py
+	coins = {
+		'btc': proto_info('Bitcoin',         'BitcoinTestnet',         5),
+		'bch': proto_info('BitcoinCash',     'BitcoinCashTestnet',     5),
+		'ltc': proto_info('Litecoin',        'LitecoinTestnet',        5),
+		'eth': proto_info('Ethereum',        'EthereumTestnet',        4),
+		'etc': proto_info('EthereumClassic', 'EthereumClassicTestnet', 4),
+		'zec': proto_info('Zcash',           'ZcashTestnet',           2),
+		'xmr': proto_info('Monero',          'MoneroTestnet',          4)
+	}
+	core_coins = tuple(coins.keys()) # coins may be added by init_genonly_altcoins(), so save
+
 # chainparams.cpp
 class BitcoinProtocol(MMGenObject):
 	name            = 'bitcoin'
@@ -118,7 +131,7 @@ class BitcoinProtocol(MMGenObject):
 
 	@staticmethod
 	def get_protocol_by_chain(chain):
-		return CoinProtocol(g.coin,{'mainnet':False,'testnet':True,'regtest':True}[chain])
+		return init_proto(g.coin,{'mainnet':False,'testnet':True,'regtest':True}[chain])
 
 	def cap(self,s): return s in self.caps
 
@@ -425,32 +438,18 @@ class MoneroProtocol(DummyWIF,BitcoinProtocolAddrgen):
 class MoneroTestnetProtocol(MoneroProtocol):
 	addr_ver_bytes = { '35': 'monero', '3f': 'monero_sub' }
 
-class CoinProtocol(MMGenObject):
-	pi = namedtuple('proto_info',['main_cls','test_cls','trust_level']) # trust levels: see altcoin.py
-	coins = {
-		'btc': pi(BitcoinProtocol,BitcoinTestnetProtocol,5),
-		'bch': pi(BitcoinCashProtocol,BitcoinCashTestnetProtocol,5),
-		'ltc': pi(LitecoinProtocol,LitecoinTestnetProtocol,5),
-		'eth': pi(EthereumProtocol,EthereumTestnetProtocol,4),
-		'etc': pi(EthereumClassicProtocol,EthereumClassicTestnetProtocol,4),
-		'zec': pi(ZcashProtocol,ZcashTestnetProtocol,2),
-		'xmr': pi(MoneroProtocol,MoneroTestnetProtocol,4)
-	}
-	core_coins = tuple(coins.keys())
-
-	def __new__(cls,coin,testnet):
-		coin = coin.lower()
-		assert type(testnet) == bool
-		m = "{}: not a valid coin for network {}\nSupported coins: {}"
-		assert coin in cls.coins, m.format(coin.upper(),g.network.upper(),' '.join(cls.list_coins()))
-		proto = cls.coins[coin][testnet]
-		if hasattr(proto,'bech32_hrps'):
-			proto.bech32_hrp = proto.bech32_hrps[('testnet','regtest')[g.regtest]]
-		return proto()
-
-	@classmethod
-	def list_coins(cls):
-		return [c.upper() for c in cls.coins]
+def init_proto(coin,testnet):
+	coin = coin.lower()
+	assert type(testnet) == bool, type(testnet)
+	if coin not in CoinProtocol.coins:
+		raise ValueError(
+			'{}: not a valid coin for network {}\nSupported coins: {}'.format(
+				coin.upper(),g.network.upper(),
+				' '.join(c.upper() for c in CoinProtocol.coins) ))
+	proto = globals()[CoinProtocol.coins[coin][testnet] + 'Protocol']
+	if hasattr(proto,'bech32_hrps'):
+		proto.bech32_hrp = proto.bech32_hrps[('testnet','regtest')[g.regtest]]
+	return proto()
 
 def init_genonly_altcoins(usr_coin=None):
 	"""
@@ -519,13 +518,13 @@ def make_init_genonly_altcoins_str(data):
 		out += make_proto(e,testnet=True)
 
 	tn_coins = [e.symbol for e in data['testnet']]
-	fs = "CoinProtocol.coins['{}'] = ({}Protocol,{})\n"
+	fs = "CoinProtocol.coins['{}'] = CoinProtocol.proto_info('{}',{},{})\n"
 	for e in data['mainnet']:
 		proto,coin = e.name,e.symbol
 		if proto[0] in '0123456789': proto = 'X_'+proto
 		if proto+'Protocol' in globals(): continue
 		if coin.lower() in CoinProtocol.coins: continue
-		out += fs.format(coin.lower(),proto,('None',proto+'TestnetProtocol')[coin in tn_coins])
+		out += fs.format(coin.lower(),proto,('None',f"'{proto}Testnet'")[coin in tn_coins],e.trust_level)
 	return out
 
 def init_coin(coin,testnet=None):
@@ -533,5 +532,5 @@ def init_coin(coin,testnet=None):
 		g.testnet = testnet
 	g.network = ('mainnet','testnet')[g.testnet]
 	g.coin = coin.upper()
-	g.proto = CoinProtocol(g.coin,g.testnet)
+	g.proto = init_proto(g.coin,g.testnet)
 	return g.proto

+ 2 - 2
mmgen/regtest.py

@@ -270,8 +270,8 @@ class MMGenRegtest(MMGenObject):
 
 	def fork(self,coin): # currently disabled
 
-		from .protocol import CoinProtocol
-		forks = CoinProtocol(coin,False).forks
+		from .protocol import init_proto
+		forks = init_proto(coin,False).forks
 		if not [f for f in forks if f[2] == g.coin.lower() and f[3] == True]:
 			die(1,"Coin {} is not a replayable fork of coin {}".format(g.coin,coin))
 

+ 4 - 1
mmgen/tool.py

@@ -1195,7 +1195,10 @@ class tool_api(
 		"""The available coins"""
 		from .protocol import CoinProtocol
 		from .altcoin import CoinInfo
-		return sorted(set(CoinProtocol.list_coins() + [c.symbol for c in CoinInfo.get_supported_coins(g.network)]))
+		return sorted(set(
+			[c.upper() for c in CoinProtocol.coins]
+			+ [c.symbol for c in CoinInfo.get_supported_coins(g.network)]
+		))
 
 	@property
 	def coin(self):

+ 1 - 1
test/gentest.py

@@ -421,7 +421,7 @@ elif not b and hasattr(arg2,'read'):
 	dump_test(a,ag,arg2)
 elif a and b and type(arg2) == int:
 	if opt.all:
-		from mmgen.protocol import init_genonly_altcoins,CoinProtocol
+		from mmgen.protocol import CoinProtocol,init_genonly_altcoins
 		init_genonly_altcoins()
 		for coin in ci.external_tests[g.network][b.desc]:
 			if coin.lower() not in CoinProtocol.coins:

+ 4 - 4
test/test_py_d/ts_regtest.py

@@ -25,7 +25,7 @@ from decimal import Decimal
 from mmgen.globalvars import g
 from mmgen.opts import opt
 from mmgen.util import die,gmsg,write_data_to_file
-from mmgen.protocol import CoinProtocol
+from mmgen.protocol import init_proto
 from mmgen.addr import AddrList
 from mmgen.wallet import MMGenWallet
 from ..include.common import *
@@ -344,7 +344,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 					x='-α' if g.debug_utf8 else ''))
 			if mmtype == g.proto.mmtypes[0] and user == 'bob':
 				psave = g.proto
-				g.proto = CoinProtocol(g.coin,True)
+				g.proto = init_proto(g.coin,True)
 				self._add_comments_to_addr_file(addrfile,addrfile,use_labels=True)
 				g.proto = psave
 			t = self.spawn( 'mmgen-addrimport',
@@ -568,7 +568,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 			sid,self.altcoin_pfx,id_str,addr_range,x='-α' if g.debug_utf8 else '')
 		addrfile = get_file_with_ext(self._user_dir(user),ext,no_dot=True)
 		psave = g.proto
-		g.proto = CoinProtocol(g.coin,True)
+		g.proto = init_proto(g.coin,True)
 		silence()
 		addr = AddrList(addrfile).data[idx].addr
 		end_silence()
@@ -810,7 +810,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 			"MMGen address '{}' not found in tracking wallet".format(addr))
 
 	def alice_add_label_badaddr4(self):
-		addr = CoinProtocol(g.coin,True).pubhash2addr('00'*20,False) # testnet zero address
+		addr = init_proto(g.coin,True).pubhash2addr('00'*20,False) # testnet zero address
 		return self.alice_add_label_badaddr(addr,
 			"Address '{}' not found in tracking wallet".format(addr))