From 1295fdb6e0c5918e1cc267f1a6cbfb0d2a01dbb5 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 4 Nov 2019 16:48:05 +0000 Subject: [PATCH] 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 --- mmgen/altcoin.py | 17 ++++++++++-- mmgen/opts.py | 5 ++-- mmgen/protocol.py | 71 ++++++++++++++++++++++++++--------------------- test/gentest.py | 5 ++-- 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/mmgen/altcoin.py b/mmgen/altcoin.py index 90d1044a..80bb7267 100755 --- a/mmgen/altcoin.py +++ b/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 diff --git a/mmgen/opts.py b/mmgen/opts.py index 59a712bd..55f67f7e 100755 --- a/mmgen/opts.py +++ b/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) diff --git a/mmgen/protocol.py b/mmgen/protocol.py index aecfc801..530b5654 100755 --- a/mmgen/protocol.py +++ b/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 diff --git a/test/gentest.py b/test/gentest.py index f9f09cc1..6e2fad44 100755 --- a/test/gentest.py +++ b/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)