Browse Source

altcoin trust level changes

- make trust level system consistent, include all coins
- rewrite init_genonly_altcoins():
  + with coin argument, create only requested protocol
  + with no arguments, create all protocols
The MMGen Project 5 years ago
parent
commit
1295fdb6e0
4 changed files with 60 additions and 38 deletions
  1. 15 2
      mmgen/altcoin.py
  2. 3 2
      mmgen/opts.py
  3. 40 31
      mmgen/protocol.py
  4. 2 3
      test/gentest.py

+ 15 - 2
mmgen/altcoin.py

@@ -41,8 +41,9 @@ ce = namedtuple('CoinInfoEntry',
 class CoinInfo(object):
 	coin_constants = {}
 	coin_constants['mainnet'] = (
-#   Trust levels: 0=untested 1=low 2=med 3=high -1=disable
-#   Fork coins must be disabled here to prevent generation from incorrect sub-seed
+#   Trust levels: -1=disabled 0=untested 1=low 2=med 3=high 4=very high (no warn) 5=unconditional
+#   Trust levels apply to key/address generation only.
+#   Fork coins must be disabled here to prevent generation from incorrect sub-seed.
 	ce('Bitcoin',               'BTC',     0x80,   (0x00,'1'),       (0x05,'3'),       True, -1),
 	ce('BitcoinSegwit2X',       'B2X',     0x80,   (0x00,'1'),       (0x05,'3'),       True, -1),
 	ce('BitcoinGold',           'BCG',     0x80,   (0x00,'1'),       (0x05,'3'),       True, -1),
@@ -385,6 +386,18 @@ class CoinInfo(object):
 		'ZRC':    ['lb','vg']
 	}
 
+	@classmethod
+	def get_supported_coins(cls,network):
+		return [e for e in cls.coin_constants[network] if e.trust_level != -1]
+
+	@classmethod
+	def get_entry(cls,coin,network):
+		try:
+			idx = [e.symbol for e in cls.coin_constants[network]].index(coin.upper())
+		except:
+			return None
+		return cls.coin_constants[network][idx]
+
 	# Data is one of the coin_constants lists above.  Normalize ints to hex of correct width, add
 	# missing leading letters, set trust level from external_tests.
 	# Insert a coin entry from outside source, set version info leading letters to '?' and trust level

+ 3 - 2
mmgen/opts.py

@@ -169,7 +169,8 @@ def override_from_env():
 			setattr(g,gname,set_for_type(val,getattr(g,gname),name,disable))
 
 def warn_altcoins(trust_level):
-	if trust_level == None: return
+	if trust_level > 3:
+		return
 	tl = (red('COMPLETELY UNTESTED'),red('LOW'),yellow('MEDIUM'),green('HIGH'))
 	m = """
 Support for coin '{}' is EXPERIMENTAL.  The {pn} project assumes no
@@ -270,7 +271,7 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
 	g.network = 'testnet' if g.testnet else 'mainnet'
 
 	from mmgen.protocol import init_genonly_altcoins,CoinProtocol
-	altcoin_trust_level = init_genonly_altcoins(opt.coin)
+	altcoin_trust_level = init_genonly_altcoins(opt.coin or 'btc')
 
 	# g.testnet is set, so we can set g.proto
 	g.proto = CoinProtocol(g.coin,g.testnet)

+ 40 - 31
mmgen/protocol.py

@@ -449,30 +449,26 @@ class MoneroTestnetProtocol(MoneroProtocol):
 	addr_ver_num = { 'monero': ('35','4'), 'monero_sub': ('3f','8') } # 53,63
 
 class CoinProtocol(MMGenObject):
+	pi = namedtuple('proto_info',['main_cls','test_cls','trust_level']) # trust levels: see altcoin.py
 	coins = {
-		#      mainnet testnet trustlevel (None == skip)
-		'btc': (BitcoinProtocol,BitcoinTestnetProtocol,None),
-		'bch': (BitcoinCashProtocol,BitcoinCashTestnetProtocol,None),
-		'ltc': (LitecoinProtocol,LitecoinTestnetProtocol,None),
-		'eth': (EthereumProtocol,EthereumTestnetProtocol,None),
-		'etc': (EthereumClassicProtocol,EthereumClassicTestnetProtocol,None),
-		'zec': (ZcashProtocol,ZcashTestnetProtocol,2),
-		'xmr': (MoneroProtocol,MoneroTestnetProtocol,None)
+		'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)
 	}
 	def __new__(cls,coin,testnet):
 		coin = coin.lower()
 		assert type(testnet) == bool
-		m = "'{}': not a valid coin. Valid choices are {}"
-		assert coin in cls.coins,m.format(coin,','.join(cls.get_valid_coins()))
+		m = "{}: not a valid coin for network {}\nSupported coins: {}"
+		assert coin in cls.coins, m.format(coin.upper(),g.network.upper(),cls.list_coins())
 		return cls.coins[coin][testnet]
 
 	@classmethod
-	def get_valid_coins(cls,upcase=False):
-		from mmgen.altcoin import CoinInfo as ci
-		ret = sorted(set(
-			[e.symbol for e in ci.coin_constants['mainnet'] if e.trust_level != -1]
-			+ list(cls.coins.keys())))
-		return [getattr(e,('lower','upper')[upcase])() for e in ret]
+	def list_coins(cls):
+		return ' '.join(c.upper() for c in cls.coins)
 
 	@classmethod
 	def get_base_coin_from_name(cls,name):
@@ -481,23 +477,36 @@ class CoinProtocol(MMGenObject):
 				return proto.base_coin
 		return False
 
-def init_genonly_altcoins(usr_coin,trust_level=None):
+def init_genonly_altcoins(usr_coin=None):
+	"""
+	Initialize altcoin protocol class or classes for current network.
+	If usr_coin is None, initializes all supported altcoins for current network.
+	Returns trust_level of usr_coin, or 0 (untrusted) if usr_coin is None.
+	"""
 	from mmgen.altcoin import CoinInfo as ci
-	if trust_level is None:
-		if not usr_coin: return None # BTC
+	data = { 'mainnet': (), 'testnet': () }
+	networks = ['mainnet'] + (['testnet'] if g.testnet else [])
+
+	if usr_coin == None:
+		for network in networks:
+			data[network] = ci.get_supported_coins(network)
+		trust_level = 0
+	else:
 		if usr_coin.lower() in CoinProtocol.coins:
-			return CoinProtocol.coins[usr_coin.lower()][2]
-		usr_coin = usr_coin.upper()
-		usr_entry = [e for e in ci.coin_constants['mainnet'] if e.symbol == usr_coin]
-		if not usr_entry:
-			raise ValueError('Coin {} not recognized'.format(usr_coin))
-		usr_entry = usr_entry[0]
-		if usr_entry.trust_level == -1:
-			raise ValueError('Coin {} ({}) not supported'.format(usr_coin,usr_entry.name))
-		trust_level = usr_entry.trust_level
-	data = {}
-	for k in ('mainnet','testnet'):
-		data[k] = [e for e in ci.coin_constants[k] if e.trust_level >= trust_level]
+			return CoinProtocol.coins[usr_coin.lower()].trust_level
+		for network in networks:
+			data[network] = (ci.get_entry(usr_coin,network),)
+
+		cinfo = data[g.network][0]
+		if not cinfo:
+			m = '{!r}: unrecognized coin for network {}'
+			raise ValueError(m.format(usr_coin.upper(),g.network.upper()))
+		if cinfo.trust_level == -1:
+			m = '{!r}: unsupported (disabled) coin for network {}'
+			raise ValueError(m.format(usr_coin.upper(),g.network.upper()))
+
+		trust_level = cinfo.trust_level
+
 	exec(make_init_genonly_altcoins_str(data),globals(),globals())
 	return trust_level
 

+ 2 - 3
test/gentest.py

@@ -351,10 +351,9 @@ ag = AddrGenerator(addr_type)
 if a and b:
 	if opt.all:
 		from mmgen.protocol import init_genonly_altcoins,CoinProtocol
-		init_genonly_altcoins('btc',trust_level=0)
-		mmgen_supported = CoinProtocol.get_valid_coins(upcase=True)
+		init_genonly_altcoins()
 		for coin in ci.external_tests[('mainnet','testnet')[g.testnet]][ext_prog]:
-			if coin not in mmgen_supported: continue
+			if coin not in CoinProtocol.coins: continue
 			init_coin(coin)
 			if addr_type not in g.proto.mmtypes:
 				addr_type = MMGenAddrType(g.proto.dfl_mmtype)