Browse Source

altcoin.py: add tests: verify_leading_symbols(), verify_core_coin_data()

The MMGen Project 6 years ago
parent
commit
3813ce33ba
3 changed files with 98 additions and 2 deletions
  1. 85 1
      mmgen/altcoin.py
  2. 2 0
      mmgen/protocol.py
  3. 11 1
      test/test-release.sh

+ 85 - 1
mmgen/altcoin.py

@@ -34,6 +34,18 @@ altcoin.py - Coin constants for Bitcoin-derived altcoins
 import sys
 import sys
 def msg(s): sys.stderr.write(s+'\n')
 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
 from collections import namedtuple
 ce = namedtuple('CoinInfoEntry',
 ce = namedtuple('CoinInfoEntry',
 	['name','symbol','wif_ver_num','p2pkh_info','p2sh_info','has_segwit','trust_level'])
 	['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('Jumbucks',              'JBS',     0xab,   (0x2b,'J'),       (0x69,'j'),       False, 2),
 	ce('Lanacoin',              'LANA',    0xb0,   (0x30,'L'),       None,             False, 0),
 	ce('Lanacoin',              'LANA',    0xb0,   (0x30,'L'),       None,             False, 0),
 	ce('Latium',                'LAT',     0x80,   (0x17,'A'),       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('LiteDoge',              'LDOGE',   0xab,   (0x5a,'d'),       None,             False, 0),
 	ce('LomoCoin',              'LMC',     0xb0,   (0x30,'L'),       None,             False, 0),
 	ce('LomoCoin',              'LMC',     0xb0,   (0x30,'L'),       None,             False, 0),
 	ce('Marscoin',              'MARS',    0xb2,   (0x32,'M'),       None,             False, 0),
 	ce('Marscoin',              'MARS',    0xb2,   (0x32,'M'),       None,             False, 0),
@@ -387,6 +399,63 @@ class CoinInfo(object):
 		'ZRC':    ['lb','vg']
 		'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
 	@classmethod
 	def get_supported_coins(cls,network):
 	def get_supported_coins(cls,network):
 		return [e for e in cls.coin_constants[network] if e.trust_level != -1]
 		return [e for e in cls.coin_constants[network] if e.trust_level != -1]
@@ -470,6 +539,9 @@ class CoinInfo(object):
 	@classmethod
 	@classmethod
 	def find_addr_leading_symbol(cls,ver_num,verbose=False):
 	def find_addr_leading_symbol(cls,ver_num,verbose=False):
 
 
+		if ver_num == 0:
+			return '1'
+
 		def phash2addr(ver_num,pk_hash):
 		def phash2addr(ver_num,pk_hash):
 			from mmgen.protocol import _b58chk_encode
 			from mmgen.protocol import _b58chk_encode
 			bl = ver_num.bit_length()
 			bl = ver_num.bit_length()
@@ -618,3 +690,15 @@ class CoinInfo(object):
 		'segwit': { 'pycoin': ('LTC',), 'keyconv': True },
 		'segwit': { 'pycoin': ('LTC',), 'keyconv': True },
 		'bech32': { '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)

+ 2 - 0
mmgen/protocol.py

@@ -458,6 +458,8 @@ class CoinProtocol(MMGenObject):
 		'zec': pi(ZcashProtocol,ZcashTestnetProtocol,2),
 		'zec': pi(ZcashProtocol,ZcashTestnetProtocol,2),
 		'xmr': pi(MoneroProtocol,MoneroTestnetProtocol,4)
 		'xmr': pi(MoneroProtocol,MoneroTestnetProtocol,4)
 	}
 	}
+	core_coins = tuple(coins.keys())
+
 	def __new__(cls,coin,testnet):
 	def __new__(cls,coin,testnet):
 		coin = coin.lower()
 		coin = coin.lower()
 		assert type(testnet) == bool
 		assert type(testnet) == bool

+ 11 - 1
test/test-release.sh

@@ -29,13 +29,14 @@ tooltest_py='test/tooltest.py'
 tooltest2_py='test/tooltest2.py --names --quiet'
 tooltest2_py='test/tooltest2.py --names --quiet'
 gentest_py='test/gentest.py --quiet'
 gentest_py='test/gentest.py --quiet'
 scrambletest_py='test/scrambletest.py'
 scrambletest_py='test/scrambletest.py'
+altcoin_py='mmgen/altcoin.py --quiet'
 mmgen_tool='cmds/mmgen-tool'
 mmgen_tool='cmds/mmgen-tool'
 mmgen_keygen='cmds/mmgen-keygen'
 mmgen_keygen='cmds/mmgen-keygen'
 python='python3'
 python='python3'
 rounds=100 rounds_min=20 rounds_mid=250 rounds_max=500
 rounds=100 rounds_min=20 rounds_mid=250 rounds_max=500
 monero_addrs='3,99,2,22-24,101-104'
 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'
 add_tests='autosign_minimal autosign_live'
 
 
 PROGNAME=$(basename $0)
 PROGNAME=$(basename $0)
@@ -80,6 +81,7 @@ do
 		echo   "     tool     - tooltest (all supported coins)"
 		echo   "     tool     - tooltest (all supported coins)"
 		echo   "     tool2    - tooltest2 (all supported coins)"
 		echo   "     tool2    - tooltest2 (all supported coins)"
 		echo   "     gen      - gentest (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"
 		echo   "  By default, all tests are run"
 		exit ;;
 		exit ;;
 	b)  test_py+=" --buf-keypress" ;;
 	b)  test_py+=" --buf-keypress" ;;
@@ -110,6 +112,7 @@ do
 	v)  EXACT_OUTPUT=1 test_py+=" --exact-output" ;&
 	v)  EXACT_OUTPUT=1 test_py+=" --exact-output" ;&
 	V)  VERBOSE=1 [ "$EXACT_OUTPUT" ] || test_py+=" --verbose"
 	V)  VERBOSE=1 [ "$EXACT_OUTPUT" ] || test_py+=" --verbose"
 		unit_tests_py="${unit_tests_py/--quiet/--verbose}"
 		unit_tests_py="${unit_tests_py/--quiet/--verbose}"
+		altcoin_py="${altcoin_py/--quiet/--verbose}"
 		tooltest2_py="${tooltest2_py/--quiet/--verbose}"
 		tooltest2_py="${tooltest2_py/--quiet/--verbose}"
 		gentest_py="${gentest_py/--quiet/--verbose}"
 		gentest_py="${gentest_py/--quiet/--verbose}"
 		tooltest_py+=" --verbose"
 		tooltest_py+=" --verbose"
@@ -196,6 +199,13 @@ do_test() {
 	done
 	done
 }
 }
 
 
+i_misc='Miscellaneous'
+s_misc='Testing various subsystems'
+t_misc="
+	$altcoin_py
+"
+f_misc='Miscellaneous tests complete'
+
 i_obj='Data object'
 i_obj='Data object'
 s_obj='Testing data objects'
 s_obj='Testing data objects'
 t_obj="
 t_obj="