From 3813ce33bacf3e7f3dfc447c1abc5b3375bcde61 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Wed, 6 Nov 2019 17:34:52 +0000 Subject: [PATCH] altcoin.py: add tests: verify_leading_symbols(), verify_core_coin_data() --- mmgen/altcoin.py | 86 +++++++++++++++++++++++++++++++++++++++++++- mmgen/protocol.py | 2 ++ test/test-release.sh | 12 ++++++- 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/mmgen/altcoin.py b/mmgen/altcoin.py index c12747b5..f467b06c 100755 --- a/mmgen/altcoin.py +++ b/mmgen/altcoin.py @@ -34,6 +34,18 @@ altcoin.py - Coin constants for Bitcoin-derived altcoins import sys def msg(s): sys.stderr.write(s+'\n') +def test_equal(desc,a,b,*cdata): + if type(a) == int: + a = hex(a) + b = hex(b) + (network,coin,e,b_desc,verbose) = cdata + if verbose: + m = ' {:20}: {!r}' + msg(m.format(desc,a)) + if a != b: + m = '{}s for {} {} do not match:\n CoinInfo: {}\n {}: {}' + raise ValueError(m.format(desc.capitalize(),coin.upper(),network,a,b_desc,b)) + from collections import namedtuple ce = namedtuple('CoinInfoEntry', ['name','symbol','wif_ver_num','p2pkh_info','p2sh_info','has_segwit','trust_level']) @@ -123,7 +135,7 @@ class CoinInfo(object): ce('Jumbucks', 'JBS', 0xab, (0x2b,'J'), (0x69,'j'), False, 2), ce('Lanacoin', 'LANA', 0xb0, (0x30,'L'), None, False, 0), ce('Latium', 'LAT', 0x80, (0x17,'A'), None, False, 0), - ce('Litecoin', 'LTC', 0xb0, (0x30,'L'), (0x05,'3'), True, 3), + ce('Litecoin', 'LTC', 0xb0, (0x30,'L'), (0x32,'M'), True, 5), # old p2sh: 0x05 ce('LiteDoge', 'LDOGE', 0xab, (0x5a,'d'), None, False, 0), ce('LomoCoin', 'LMC', 0xb0, (0x30,'L'), None, False, 0), ce('Marscoin', 'MARS', 0xb2, (0x32,'M'), None, False, 0), @@ -387,6 +399,63 @@ class CoinInfo(object): 'ZRC': ['lb','vg'] } + @classmethod + def verify_leading_symbols(cls,quiet=False,verbose=False): + + for network in ('mainnet','testnet'): + for coin in [e.symbol for e in cls.coin_constants[network]]: + e = cls.get_entry(coin,network) + cdata = (network,coin,e,'Computed value',verbose) + + if not quiet: + msg('{} {}'.format(coin,network)) + + vn_info = e.p2pkh_info + ret = cls.find_addr_leading_symbol(vn_info[0]) + test_equal('P2PKH leading symbol',vn_info[1],ret,*cdata) + + vn_info = e.p2sh_info + if vn_info: + ret = cls.find_addr_leading_symbol(vn_info[0]) + test_equal('P2SH leading symbol',vn_info[1],ret,*cdata) + + @classmethod + def verify_core_coin_data(cls,quiet=False,verbose=False): + from mmgen.protocol import CoinProtocol + + 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') + cdata = (network,coin,e,proto.__name__,verbose) + if not quiet: + msg('Verifying {} {}'.format(coin.upper(),network)) + + if coin != 'bch': # TODO + test_equal('coin name',e.name,proto.name.capitalize(),*cdata) + + if e.trust_level != -1: + test_equal('Trust level',e.trust_level,CoinProtocol.coins[coin].trust_level,*cdata) + + test_equal( + 'WIF version number', + e.wif_ver_num, + int.from_bytes(bytes.fromhex(proto.wif_ver_num['std']),'big'), + *cdata ) + + test_equal( + 'P2PKH version number', + e.p2pkh_info[0], + int.from_bytes(proto.addr_fmt_to_ver_bytes('p2pkh'),'big'), + *cdata ) + + test_equal( + 'P2SH version number', + e.p2sh_info[0], + int.from_bytes(proto.addr_fmt_to_ver_bytes('p2sh'),'big'), + *cdata ) + @classmethod def get_supported_coins(cls,network): return [e for e in cls.coin_constants[network] if e.trust_level != -1] @@ -470,6 +539,9 @@ class CoinInfo(object): @classmethod def find_addr_leading_symbol(cls,ver_num,verbose=False): + if ver_num == 0: + return '1' + def phash2addr(ver_num,pk_hash): from mmgen.protocol import _b58chk_encode bl = ver_num.bit_length() @@ -618,3 +690,15 @@ class CoinInfo(object): 'segwit': { 'pycoin': ('LTC',), 'keyconv': True }, 'bech32': { 'keyconv': True }, } + +if __name__ == '__main__': + quiet = '--quiet' in sys.argv + verbose = '--verbose' in sys.argv + if verbose: + quiet = False + + msg('Checking CoinInfo WIF/P2PKH/P2SH version numbers and trust levels against protocol.py') + CoinInfo.verify_core_coin_data(quiet=quiet,verbose=verbose) + + msg('Checking CoinInfo address leading symbols') + CoinInfo.verify_leading_symbols(quiet=quiet,verbose=verbose) diff --git a/mmgen/protocol.py b/mmgen/protocol.py index 83ce786c..6130a01e 100755 --- a/mmgen/protocol.py +++ b/mmgen/protocol.py @@ -458,6 +458,8 @@ class CoinProtocol(MMGenObject): '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 diff --git a/test/test-release.sh b/test/test-release.sh index 5ca081f1..8b476f44 100755 --- a/test/test-release.sh +++ b/test/test-release.sh @@ -29,13 +29,14 @@ tooltest_py='test/tooltest.py' tooltest2_py='test/tooltest2.py --names --quiet' gentest_py='test/gentest.py --quiet' scrambletest_py='test/scrambletest.py' +altcoin_py='mmgen/altcoin.py --quiet' mmgen_tool='cmds/mmgen-tool' mmgen_keygen='cmds/mmgen-keygen' python='python3' rounds=100 rounds_min=20 rounds_mid=250 rounds_max=500 monero_addrs='3,99,2,22-24,101-104' -dfl_tests='obj color unit hash ref alts monero eth autosign btc btc_tn btc_rt bch bch_rt ltc ltc_tn ltc_rt tool tool2 gen' +dfl_tests='misc obj color unit hash ref alts monero eth autosign btc btc_tn btc_rt bch bch_rt ltc ltc_tn ltc_rt tool tool2 gen' add_tests='autosign_minimal autosign_live' PROGNAME=$(basename $0) @@ -80,6 +81,7 @@ do echo " tool - tooltest (all supported coins)" echo " tool2 - tooltest2 (all supported coins)" echo " gen - gentest (all supported coins)" + echo " misc - miscellaneous tests that don't fit in the above categories" echo " By default, all tests are run" exit ;; b) test_py+=" --buf-keypress" ;; @@ -110,6 +112,7 @@ do v) EXACT_OUTPUT=1 test_py+=" --exact-output" ;& V) VERBOSE=1 [ "$EXACT_OUTPUT" ] || test_py+=" --verbose" unit_tests_py="${unit_tests_py/--quiet/--verbose}" + altcoin_py="${altcoin_py/--quiet/--verbose}" tooltest2_py="${tooltest2_py/--quiet/--verbose}" gentest_py="${gentest_py/--quiet/--verbose}" tooltest_py+=" --verbose" @@ -196,6 +199,13 @@ do_test() { done } +i_misc='Miscellaneous' +s_misc='Testing various subsystems' +t_misc=" + $altcoin_py +" +f_misc='Miscellaneous tests complete' + i_obj='Data object' s_obj='Testing data objects' t_obj="