rewrite test/gentest.py utility

- support for testing all configured generators in one go has also been added
  (via the 'all' subparameter)
This commit is contained in:
The MMGen Project 2022-01-15 14:00:11 +00:00
commit b43d827b50
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 270 additions and 220 deletions

View file

@ -30,68 +30,88 @@ sys.path.insert(0,overlay_setup(repo_root))
from mmgen.common import *
from test.include.common import getrand
results_file = 'gentest.out.json'
rounds = 100
opts_data = {
'text': {
'desc': 'Test key/address generation of the MMGen suite in various ways',
'usage':'[options] [spec] [rounds | dump file]',
'usage':'[options] <spec> <rounds | dump file>',
'options': """
-h, --help Print this help message
-a, --all Test all coins supported by specified external tool
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-a, --all-coins Test all coins supported by specified external tool
-k, --use-internal-keccak-module Force use of the internal keccak module
--, --longhelp Print help message for long options (common options)
-q, --quiet Produce quieter output
-t, --type=t Specify address type (e.g. 'compressed','segwit','zcash_z','bech32')
-v, --verbose Produce more verbose output
-q, --quiet Produce quieter output
-s, --save-results Save output of external tool in Compare test to
{rf!r}
-t, --type=t Specify address type (e.g. 'compressed','segwit',
'zcash_z','bech32')
-v, --verbose Produce more verbose output
""",
'notes': """
TEST TYPES:
A/B: {prog} A:B [rounds] (compare key generators A and B)
Speed: {prog} A [rounds] (test speed of key generator A)
Compare: {prog} A <dump file> (compare generator A to wallet dump)
Compare: {prog} A:B <rounds> (compare address generators A and B)
Speed: {prog} A <rounds> (test speed of generator A)
Dump: {prog} A <dump file> (compare generator A to wallet dump)
where A and B are one of:
'1' - native Python ECDSA library (slow), or
'2' - bitcoincore.org's libsecp256k1 library (default);
or:
B is name of an external tool (see below) or 'ext'.
If B is 'ext', the external tool will be chosen automatically.
where:
A and B are keygen backend numbers ('1' being the default); or
B is the name of an external tool (see below) or 'ext'.
If B is 'ext', the external tool will be chosen automatically.
For the Compare test, A may be 'all' to test all backends for the current
coin/address type combination.
EXAMPLES:
Compare addresses generated by native Python ECDSA library and libsecp256k1,
100 rounds:
Compare addresses generated by 'libsecp256k1' and 'python-ecdsa' backends,
with 100 random rounds plus private-key edge cases:
$ {prog} 1:2 100
Compare mmgen-secp256k1 Segwit address generation to pycoin library for all
supported coins, 100 rounds:
$ {prog} --all --type=segwit 2:pycoin 100
Compare Segwit addresses from default 'libsecp256k1' backend to 'pycoin'
library for all supported coins, 100 rounds + edge cases:
$ {prog} --all-coins --type=segwit 1:pycoin 100
Compare mmgen-secp256k1 address generation to keyconv tool for all
supported coins, 100 rounds:
$ {prog} --all --type=compressed 2:keyconv 100
Compare addresses from 'python-ecdsa' backend to output of 'keyconv' tool
for all supported coins, 100 rounds + edge cases:
$ {prog} --all-coins --type=compressed 2:keyconv 100
Compare mmgen-secp256k1 XMR address generation to configured external tool,
10 rounds:
$ {prog} --coin=xmr 2:ext 10
Compare bech32 addrs from 'libsecp256k1' backend to Bitcoin Core wallet
dump:
$ {prog} --type=bech32 1 bech32wallet.dump
Test speed of mmgen-secp256k1 address generation, 10,000 rounds:
$ {prog} 2 10000
Compare addresses from Monero 'ed25519ll' backend to output of default
external tool, 10 rounds + edge cases:
$ {prog} --coin=xmr 3:ext 10
Compare mmgen-secp256k1-generated bech32 addrs to coin daemon wallet dump:
$ {prog} --type=bech32 2 bech32wallet.dump
Test the speed of default Monero 'nacl' backend, 10,000 rounds:
$ test/gentest.py --coin=xmr 1 10000
Supported external tools:
Same for Zcash:
$ test/gentest.py --coin=zec --type=zcash_z 1 10000
Test all configured Monero backends against 'moneropy' library, 3 rounds
+ edge cases:
$ test/gentest.py --coin=xmr all:moneropy 3
Test 'nacl' and 'ed25519ll_djbec' backends against each other, 10,000 rounds
+ edge cases:
$ test/gentest.py --coin=xmr 1:2 10000
SUPPORTED EXTERNAL TOOLS:
+ ethkey (for ETH,ETC)
https://github.com/openethereum/openethereum
https://github.com/openethereum/openethereum
(build with 'cargo build -p ethkey-cli --release')
+ zcash-mini (for Zcash Z-addresses)
+ zcash-mini (for Zcash-Z addresses and view keys)
https://github.com/FiloSottile/zcash-mini
+ moneropy (for Monero addresses)
+ moneropy (for Monero addresses and view keys)
https://github.com/bigreddmachine/MoneroPy
+ pycoin (for supported coins)
@ -103,6 +123,9 @@ Supported external tools:
"""
},
'code': {
'options': lambda s: s.format(
rf=results_file,
),
'notes': lambda s: s.format(
prog='test/gentest.py',
pnm=g.proj_name,
@ -110,36 +133,33 @@ Supported external tools:
}
}
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]
gtr = namedtuple('gen_tool_result',['wif','addr','vk'])
cmd_args = opts.init(opts_data,add_opts=['exact_output'])
if not 1 <= len(cmd_args) <= 2:
opts.usage()
from mmgen.protocol import init_proto_from_opts
proto = init_proto_from_opts()
from subprocess import run,PIPE,DEVNULL
def get_cmd_output(cmd,input=None):
return run(cmd,input=input,stdout=PIPE,stderr=DEVNULL).stdout.decode().splitlines()
from collections import namedtuple
gtr = namedtuple('gen_tool_result',['wif','addr','vk'])
saved_results = {}
class GenTool(object):
def __init__(self,proto,addr_type):
self.proto = proto
self.addr_type = addr_type
self.data = {}
def __del__(self):
if opt.save_results:
key = f'{self.proto.coin}-{self.proto.network}-{self.addr_type.name}-{self.desc}'.lower()
saved_results[key] = self.data
def run_tool(self,sec):
vcoin = 'BTC' if proto.coin == 'BCH' else proto.coin
return self.run(sec,vcoin)
vcoin = 'BTC' if self.proto.coin == 'BCH' else self.proto.coin
ret = self.run(sec,vcoin)
self.data[sec] = ret._asdict()
return ret
class GenToolEthkey(GenTool):
desc = 'ethkey'
def __init__(self):
proto = init_proto('eth')
global addr_type
addr_type = MMGenAddrType(proto,'E')
def run(self,sec,vcoin):
o = get_cmd_output(['ethkey','info',sec])
return gtr(o[0].split()[1],o[-1].split()[1],None)
@ -152,11 +172,6 @@ class GenToolKeyconv(GenTool):
class GenToolZcash_mini(GenTool):
desc = 'zcash-mini'
def __init__(self):
proto = init_proto('zec')
global addr_type
addr_type = MMGenAddrType(proto,'Z')
def run(self,sec,vcoin):
o = get_cmd_output(['zcash-mini','-key','-simple'],input=(sec.wif+'\n').encode())
return gtr(o[1],o[0],o[-1])
@ -166,24 +181,26 @@ class GenToolPycoin(GenTool):
pycoin/networks/all.py pycoin/networks/legacy_networks.py
"""
desc = 'pycoin'
def __init__(self):
m = "Unable to import pycoin.networks.registry. Is pycoin installed on your system?"
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
try:
from pycoin.networks.registry import network_for_netcode
except:
raise ImportError(m)
raise ImportError('Unable to import pycoin.networks.registry. Is pycoin installed on your system?')
self.nfnc = network_for_netcode
def run(self,sec,vcoin):
if proto.testnet:
if self.proto.testnet:
vcoin = ci.external_tests['testnet']['pycoin'][vcoin]
network = self.nfnc(vcoin)
key = network.keys.private(secret_exponent=int(sec,16),is_compressed=addr_type.name != 'legacy')
key = network.keys.private(
secret_exponent = int(sec,16),
is_compressed = self.addr_type.name != 'legacy' )
if key is None:
die(1,f'can’t parse {sec}')
if addr_type.name in ('segwit','bech32'):
if self.addr_type.name in ('segwit','bech32'):
hash160_c = key.hash160(is_compressed=True)
if addr_type.name == 'segwit':
if self.addr_type.name == 'segwit':
p2sh_script = network.contract.for_p2pkh_wit(hash160_c)
addr = network.address.for_p2s(p2sh_script)
else:
@ -194,44 +211,42 @@ class GenToolPycoin(GenTool):
class GenToolMoneropy(GenTool):
desc = 'moneropy'
def __init__(self):
m = "Unable to import moneropy. Is moneropy installed on your system?"
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
try:
import moneropy.account
except:
raise ImportError(m)
raise ImportError('Unable to import moneropy. Is moneropy installed on your system?')
self.mpa = moneropy.account
proto = init_proto('xmr')
global addr_type
addr_type = MMGenAddrType(proto,'M')
def run(self,sec,vcoin):
sk_t,vk_t,addr_t = self.mpa.account_from_spend_key(sec) # VERY slow!
return gtr(sk_t,addr_t,vk_t)
if sec in self.data:
return gtr(**self.data[sec])
else:
sk,vk,addr = self.mpa.account_from_spend_key(sec) # VERY slow!
return gtr(sk,addr,vk)
def get_tool(arg):
def find_or_check_tool(proto,addr_type,toolname):
if arg not in ext_progs + ['ext']:
die(1,f'{arg!r}: unsupported tool for network {proto.network}')
ext_progs = list(ci.external_tests[proto.network])
if opt.all:
if arg == 'ext':
die(1,"'--all' must be combined with a specific external testing tool")
return arg
if toolname not in ext_progs + ['ext']:
die(1,f'{toolname!r}: unsupported tool for network {proto.network}')
if opt.all_coins and toolname == 'ext':
die(1,"'--all-coins' must be combined with a specific external testing tool")
else:
tool = ci.get_test_support(
proto.coin,
addr_type.name,
proto.network,
verbose = not opt.quiet,
tool = arg if arg in ext_progs else None )
if not tool:
sys.exit(2)
if arg in ext_progs and arg != tool:
tool = toolname if toolname != 'ext' else None )
if tool and toolname in ext_progs and toolname != tool:
sys.exit(3)
if tool == None:
return None
return tool
def test_equal(desc,a_val,b_val,in_bytes,sec,wif,a_desc,b_desc):
@ -251,13 +266,47 @@ def test_equal(desc,a_val,b_val,in_bytes,sec,wif,a_desc,b_desc):
w=max(len(e) for e in (a_desc,b_desc)) + 1
).rstrip())
def gentool_test(kg_a,kg_b,ag,rounds):
def do_ab_test(proto,addr_type,kg_b,rounds,backend_num):
def run_ab_inner(n,trounds,in_bytes):
global last_t
if opt.verbose or time.time() - last_t >= 0.1:
qmsg_r(f'\rRound {i+1}/{trounds} ')
last_t = time.time()
sec = PrivKey(proto,in_bytes,compressed=addr_type.compressed,pubkey_type=addr_type.pubkey_type)
data = kg_a.to_pubhex(sec)
ag = AddrGenerator(proto,addr_type)
a_addr = ag.to_addr(data)
tinfo = (in_bytes,sec,sec.wif,type(kg_a).__name__,type(kg_b).__name__)
a_vk = None
def do_msg():
vmsg( fs.format( b=in_bytes.hex(), r=sec, k=sec.wif, v=a_vk, a=a_addr ))
if isinstance(kg_b,GenTool):
def run_tool():
b = kg_b.run_tool(sec)
test_equal('WIF keys',sec.wif,b.wif,*tinfo)
test_equal('addresses',a_addr,b.addr,*tinfo)
if b.vk:
test_equal( 'view keys', ag.to_viewkey(data), b.vk, *tinfo )
return b.vk
a_vk = run_tool()
do_msg()
else:
test_equal( 'addresses', a_addr, ag.to_addr(kg_b.to_pubhex(sec)), *tinfo )
do_msg()
qmsg_r(f'\rRound {n+1}/{trounds} ')
kg_a = KeyGenerator(proto,addr_type,backend_num)
if type(kg_a) == type(kg_b):
rdie(1,'Key generators are the same!')
m = "Comparing address generators '{A}' and '{B}' for {N} {c} ({n}), addrtype {a!r}"
e = ci.get_entry(proto.coin,proto.network)
qmsg(green(m.format(
A = kg_a.desc,
B = kg_b.desc,
qmsg(green("Comparing address generators '{A}' and '{B}' for {N} {c} ({n}), addrtype {a!r}".format(
A = type(kg_a).__name__,
B = type(kg_b).__name__.replace('GenTool','').replace('_','-').lower(),
N = proto.network,
c = proto.coin,
n = e.name if e else '---',
@ -266,61 +315,71 @@ def gentool_test(kg_a,kg_b,ag,rounds):
global last_t
last_t = time.time()
def do_compare_test(n,trounds,in_bytes):
global last_t
if opt.verbose or time.time() - last_t >= 0.1:
qmsg_r(f'\rRound {i+1}/{trounds} ')
last_t = time.time()
sec = PrivKey(proto,in_bytes,compressed=addr_type.compressed,pubkey_type=addr_type.pubkey_type)
a_ph = kg_a.to_pubhex(sec)
a_addr = ag.to_addr(a_ph)
a_vk = None
tinfo = (in_bytes,sec,sec.wif,kg_a.desc,kg_b.desc)
if isinstance(kg_b,GenTool):
b = kg_b.run_tool(sec)
test_equal('WIF keys',sec.wif,b.wif,*tinfo)
test_equal('addresses',a_addr,b.addr,*tinfo)
if b.vk:
a_vk = ag.to_viewkey(a_ph)
test_equal('view keys',a_vk,b.vk,*tinfo)
else:
b_addr = ag.to_addr(kg_b.to_pubhex(sec))
test_equal('addresses',a_addr,b_addr,*tinfo)
vmsg(fs.format(b=in_bytes.hex(),k=sec.wif,v=a_vk,a=a_addr))
qmsg_r(f'\rRound {n+1}/{trounds} ')
fs = (
'\ninput: {b}' +
'\nreduced: {r}' +
'\n{:9} {{k}}'.format(addr_type.wif_label+':') +
('\nviewkey: {v}' if 'viewkey' in addr_type.extra_attrs else '') +
'\naddr: {a}\n' )
fs = ( '\ninput: {b}\n%-9s {k}\naddr: {a}\n',
'\ninput: {b}\n%-9s {k}\nviewkey: {v}\naddr: {a}\n')[
'viewkey' in addr_type.extra_attrs] % (addr_type.wif_label + ':')
ge = CoinProtocol.Secp256k1.secp256k1_ge
# test some important private key edge cases:
edgecase_sks = (
bytes([0x00]*31 + [0x01]), # min
bytes([0xff]*32), # max
bytes([0x0f] + [0xff]*31), # same key as above for zcash-z
bytes([0x0f] + [0xff]*31), # produces same key as above for zcash-z
int.to_bytes(ge + 1, 32, 'big'), # bitcoin will reduce
int.to_bytes(ge - 1, 32, 'big'), # bitcoin will not reduce
bytes([0x00]*31 + [0xff]), # monero will reduce
bytes([0xff]*31 + [0x0f]), # monero will not reduce
bytes.fromhex('deadbeef'*8),
)
qmsg(purple('edge cases:'))
for i,in_bytes in enumerate(edgecase_sks):
do_compare_test(i,len(edgecase_sks),in_bytes)
run_ab_inner(i,len(edgecase_sks),in_bytes)
qmsg(green('\rOK ' if opt.verbose else 'OK'))
qmsg(purple('random input:'))
for i in range(rounds):
do_compare_test(i,rounds,getrand(32))
run_ab_inner(i,rounds,getrand(32))
qmsg(green('\rOK ' if opt.verbose else 'OK'))
def speed_test(kg,ag,rounds):
m = "Testing speed of address generator '{}' for coin {}"
qmsg(green(m.format(kg.desc,proto.coin)))
def init_tool(proto,addr_type,toolname):
return globals()['GenTool'+capfirst(toolname.replace('-','_'))](proto,addr_type)
def get_backends(proto,foo):
return (1,) if isinstance(proto,CoinProtocol.Zcash) else (1,2)
def ab_test(proto,gen_num,rounds,toolname_or_gen2_num):
addr_type = MMGenAddrType( proto=proto, id_str=opt.type or proto.dfl_mmtype )
if is_int(toolname_or_gen2_num):
assert gen_num != 'all', "'all' must be used only with external tool"
tool = KeyGenerator( proto, addr_type, int(toolname_or_gen2_num) )
else:
toolname = find_or_check_tool( proto, addr_type, toolname_or_gen2_num )
if toolname == None:
ymsg(f'Warning: skipping tool {toolname_or_gen2_num!r} for {proto.coin} {addr_type.name}')
return
tool = init_tool( proto, addr_type, toolname )
if gen_num == 'all': # check all backends against external tool
for n in range(len(get_backends(proto,addr_type.pubkey_type))):
do_ab_test( proto, addr_type, tool, rounds, n+1 )
else: # check specific backend against external tool or another backend
do_ab_test( proto, addr_type, tool, rounds, int(gen_num) )
def speed_test(proto,addr_type,kg,ag,rounds):
qmsg(green('Testing speed of address generator {!r} for coin {}'.format(
type(kg).__name__,
proto.coin )))
from struct import pack,unpack
seed = getrand(28)
qmsg('Incrementing key with each round')
qmsg('Starting key: {}'.format(
(seed + pack('I',0)).hex()
))
qmsg('Starting key: {}'.format( (seed + pack('I',0)).hex() ))
import time
start = last_t = time.time()
@ -328,7 +387,7 @@ def speed_test(kg,ag,rounds):
if time.time() - last_t >= 0.1:
qmsg_r(f'\rRound {i+1}/{rounds} ')
last_t = time.time()
sec = PrivKey(proto,seed+pack('I',i),compressed=addr_type.compressed,pubkey_type=addr_type.pubkey_type)
sec = PrivKey( proto, seed+pack('I', i), compressed=addr_type.compressed, pubkey_type=addr_type.pubkey_type )
addr = ag.to_addr(kg.to_pubhex(sec))
vmsg(f'\nkey: {sec.wif}\naddr: {addr}\n')
qmsg(
@ -337,15 +396,18 @@ def speed_test(kg,ag,rounds):
('' if g.test_suite_deterministic else f' in {time.time()-start:.2f} seconds')
)
def dump_test(kg,ag,fh):
def dump_test(proto,kg,ag,filename):
dump = [[*(e.split()[0] for e in line.split('addr='))] for line in fh.readlines() if 'addr=' in line]
if not dump:
die(1,f'File {fh.name!r} appears not to be a wallet dump')
fh.close()
with open(filename) as fp:
dump = [[*(e.split()[0] for e in line.split('addr='))] for line in fp.readlines() if 'addr=' in line]
if not dump:
die(1,f'File {filename!r} appears not to be a wallet dump')
m = 'Comparing output of address generator {!r} against wallet dump {!r}'
qmsg(green(m.format(kg.desc,fh.name)))
qmsg(green(
"A: generator pair '{}:{}'\nB: wallet dump {!r}".format(
type(kg).__name__,
type(ag).__name__,
filename)))
for count,(b_wif,b_addr) in enumerate(dump,1):
qmsg_r(f'\rKey {count}/{len(dump)} ')
@ -355,102 +417,90 @@ def dump_test(kg,ag,fh):
die(2,f'\nInvalid {proto.network} WIF address in dump file: {b_wif}')
a_addr = ag.to_addr(kg.to_pubhex(b_sec))
vmsg(f'\nwif: {b_wif}\naddr: {b_addr}\n')
tinfo = (bytes.fromhex(b_sec),b_sec,b_wif,kg.desc,fh.name)
tinfo = (b_sec,b_sec,b_wif,type(kg).__name__,filename)
test_equal('addresses',a_addr,b_addr,*tinfo)
qmsg(green(('\n','')[bool(opt.verbose)] + 'OK'))
def init_tool(tname):
return globals()['GenTool'+capfirst(tname.replace('-','_'))]()
def get_protos(proto,addr_type,toolname):
def parse_arg1(arg,arg_id):
init_genonly_altcoins(testnet=proto.testnet)
m1 = 'First argument must be a numeric generator ID or two colon-separated generator IDs'
m2 = 'Second part of first argument must be a numeric generator ID or one of {}'
for coin in ci.external_tests[proto.network][toolname]:
if coin.lower() not in CoinProtocol.coins:
continue
ret = init_proto(coin,testnet=proto.testnet)
if addr_type not in ret.mmtypes:
continue
yield ret
def check_gen_num(n):
if not (1 <= int(n) <= len(g.key_generators)):
die(1,f'{n}: invalid generator ID')
return int(n)
def parse_args():
if arg_id == 'a':
if is_int(arg):
a_num = check_gen_num(arg)
return (KeyGenerator(proto,addr_type,a_num),a_num)
else:
die(1,m1)
elif arg_id == 'b':
if is_int(arg):
return KeyGenerator(proto,addr_type,check_gen_num(arg))
elif arg in ext_progs + ['ext']:
return init_tool(get_tool(arg))
else:
die(1,m2.format(ext_progs))
if len(cmd_args) != 2:
opts.usage()
arg1,arg2 = cmd_args
pa = namedtuple('parsed_args',['test','gen_num','rounds','arg'])
if is_int(arg1) and is_int(arg2):
return pa( test='speed', gen_num=arg1, rounds=int(arg2), arg=None )
if is_int(arg1) and os.access(arg2,os.R_OK):
return pa( test='dump', gen_num=arg1, rounds=None, arg=arg2 )
if not is_int(arg2):
die(1,'Second argument must be dump filename or integer rounds specification')
def parse_arg2():
m = 'Second argument must be dump filename or integer rounds specification'
if len(cmd_args) == 1:
return None
arg = cmd_args[1]
if is_int(arg) and int(arg) > 0:
return int(arg)
try:
return open(arg)
a,b = arg1.split(':')
except:
die(1,m)
die(1,'First argument must be a generator backend number or two colon-separated arguments')
# begin execution
from mmgen.protocol import init_proto
if not is_int(a) and a != 'all':
die(1,"First part of first argument must be a generator backend number or 'all'")
if is_int(b):
if opt.all_coins:
die(1,'--all-coins must be used with external tool only')
else:
proto = init_proto_from_opts()
ext_progs = list(ci.external_tests[proto.network]) + ['ext']
if b not in ext_progs:
die(1,f'Second part of first argument must be a generator backend number or one of {ext_progs}')
return pa( test='ab', gen_num=a, rounds=int(arg2), arg=b )
def main():
pa = parse_args()
proto = init_proto_from_opts()
addr_type = MMGenAddrType( proto=proto, id_str=opt.type or proto.dfl_mmtype )
if pa.test == 'ab':
protos = get_protos(proto,addr_type,pa.arg) if opt.all_coins else [proto]
for proto in protos:
ab_test( proto, pa.gen_num, pa.rounds, toolname_or_gen2_num=pa.arg )
else:
kg = KeyGenerator( proto, addr_type, pa.gen_num )
ag = AddrGenerator( proto, addr_type )
if pa.test == 'speed':
speed_test( proto, addr_type, kg, ag, pa.rounds )
elif pa.test == 'dump':
dump_test( proto, kg, ag, filename=pa.arg )
if saved_results:
import json
with open(results_file,'w') as fp:
fp.write(json.dumps( saved_results, indent=4 ))
from subprocess import run,PIPE,DEVNULL
from collections import namedtuple
from mmgen.protocol import init_proto,init_proto_from_opts,CoinProtocol,init_genonly_altcoins
from mmgen.altcoin import CoinInfo as ci
from mmgen.key import PrivKey
from mmgen.addr import KeyGenerator,AddrGenerator,MMGenAddrType
addr_type = MMGenAddrType(
proto = proto,
id_str = opt.type or proto.dfl_mmtype )
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]
cmd_args = opts.init(opts_data,add_opts=['exact_output'])
ext_progs = list(ci.external_tests[proto.network])
arg1 = cmd_args[0].split(':')
if len(arg1) == 1:
a,a_num = parse_arg1(arg1[0],'a')
b = None
elif len(arg1) == 2:
a,a_num = parse_arg1(arg1[0],'a')
b = parse_arg1(arg1[1],'b')
else:
opts.usage()
if type(a) == type(b):
rdie(1,'Address generators are the same!')
arg2 = parse_arg2()
if not opt.all:
ag = AddrGenerator(proto,addr_type)
if not b and type(arg2) == int:
speed_test(a,ag,arg2)
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 CoinProtocol,init_genonly_altcoins
init_genonly_altcoins(testnet=proto.testnet)
for coin in ci.external_tests[proto.network][b.desc]:
if coin.lower() not in CoinProtocol.coins:
# ymsg(f'Coin {coin} not configured')
continue
proto = init_proto(coin)
if addr_type not in proto.mmtypes:
continue
# proto has changed, so reinit kg and ag
a = KeyGenerator(proto,addr_type,a_num)
ag = AddrGenerator(proto,addr_type)
b_chk = ci.get_test_support(proto.coin,addr_type.name,proto.network,tool=b.desc,verbose=not opt.quiet)
if b_chk == b.desc:
gentool_test(a,b,ag,arg2)
else:
gentool_test(a,b,ag,arg2)
else:
opts.usage()
main()

View file

@ -330,7 +330,7 @@ t_alts="
m # moneropy
m $gentest_py --all --coin=xmr 2:moneropy $rounds_min # very slow, be patient!
z # zcash-mini
z $gentest_py --all 2:zcash-mini $rounds_mid
z $gentest_py --all --coin=zec --type=zcash_z 1:zcash-mini $rounds_mid
"
[ "$MSYS2" ] && t_alts_skip='m z' # no moneropy (pysha3), zcash-mini (golang)