diff --git a/mmgen/addr.py b/mmgen/addr.py index 595e3ebe..eb727007 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -49,13 +49,13 @@ faster address generation. """.format(kcexe=g.keyconv_exec, vanityg="vanitygen") } -def test_for_keyconv(): +def test_for_keyconv(silent=False): from subprocess import check_output,STDOUT try: check_output([g.keyconv_exec, '-G'],stderr=STDOUT) except: - msg(addrmsgs['no_keyconv_msg']) + if not silent: msg(addrmsgs['no_keyconv_msg']) return False return True diff --git a/test/gentest.py b/test/gentest.py new file mode 100755 index 00000000..8b5b1940 --- /dev/null +++ b/test/gentest.py @@ -0,0 +1,77 @@ +#!/usr/bin/python + +# Chdir to repo root. +# Since script is not in repo root, fix sys.path so that modules are +# imported from repo, not system. +import sys,os +pn = os.path.dirname(sys.argv[0]) +os.chdir(os.path.join(pn,os.pardir)) +sys.path.__setitem__(0,os.path.abspath(os.curdir)) + +from binascii import hexlify + +import mmgen.opt as opt +import mmgen.config as g +from mmgen.util import msg,msg_r,msgrepr,msgrepr_exit,red,green +from mmgen.bitcoin import hextowif,privnum2addr + +rounds = 100 +opts_data = { + 'desc': "Test addresses generated by {} against output of 'keyconv'".format(g.proj_name), + 'usage':"[options] [rounds]", + 'options': """ +-h, --help Print this help message +-s, --system Test scripts and modules installed on system rather than + those in the repo root +""", + 'notes': """ + +'keyconv' is the address generation utility from the well-known vanitygen +package. If it's installed on your system, {pnm} will use it by default to +generate Bitcoin addresses. Otherwise, it falls back on its own internal +routines, which use the Python ecdsa library. + +rounds is {} by default. +""".format(rounds,pnm=g.proj_name) +} +cmd_args = opt.opts.init(opts_data,add_opts=["exact_output"]) + +if len(cmd_args) == 1: + try: + rounds = int(cmd_args[0]) + assert rounds > 0 + except: + msg("'rounds' must be a positive integer") + sys.exit(1) + +elif len(cmd_args) > 1: + opt.opts.usage(opts_data) + +if opt.system: sys.path.pop(0) + +from mmgen.addr import test_for_keyconv +if not test_for_keyconv(silent=True): + msg( +"To run this test, you must install 'keyconv' from the vanitygen package.") + sys.exit(1) + +msg(green("Comparing {}'s internally generated addresses against output of 'keyconv'").format(g.proj_name)) + +from subprocess import check_output +for i in range(1,rounds+1): + msg_r("\rRound %s/%s " % (i,rounds)) + sec = hexlify(os.urandom(32)) + wif = hextowif(sec) + a = privnum2addr(int(sec,16)) + b = check_output(["keyconv", wif]).split()[1] + if a != b: + msg_r(red("\nERROR: Addresses do not match!")) + msg(""" + sec key: {} + WIF key: {} + {pnm}: {} + keyconv: {} +""".format(sec,wif,a,b,pnm=g.proj_name).rstrip()) + sys.exit(3) + +msg(green("\nOK")) diff --git a/test/test.py b/test/test.py index 6247ba2c..e8ec12fd 100755 --- a/test/test.py +++ b/test/test.py @@ -13,7 +13,12 @@ import mmgen.opt as opt from mmgen.util import msgrepr,msgrepr_exit,Msg from mmgen.test import * -hincog_fn = "rand_data" +hincog_fn = "rand_data" +hincog_bytes = 1024*1024 +hincog_offset = 98765 +hincog_seedlen = 256 + +incog_id_fn = "incog_id" non_mmgen_fn = "btckey" cfgs = { @@ -51,7 +56,8 @@ cfgs = { 'mmseed': "export_seed", 'mmincog': "export_incog", 'mmincox': "export_incog_hex", - hincog_fn: "export_incog_hidden", + hincog_fn: "export_incog_hidden", + incog_id_fn: "export_incog_hidden", 'akeys.mmenc': "keyaddrgen" }, }, @@ -175,6 +181,7 @@ cmd_data = OrderedDict([ ['tool_decrypt_ref', (9,"'mmgen-tool decrypt' (reference text)", [[[cfgs['9']['tool_enc_ref_infn'], cfgs['9']['tool_enc_ref_infn']+".mmenc"],9]])], + ['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])], ]) utils = { @@ -201,7 +208,7 @@ meta_cmds = OrderedDict([ ['2', (2,[k for k in cmd_data if cmd_data[k][0] == 2])], ['3', (3,[k for k in cmd_data if cmd_data[k][0] == 3])], ['4', (4,[k for k in cmd_data if cmd_data[k][0] == 4])], - ['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref"))], + ['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref","tool_find_incog_data"))], ]) opts_data = { @@ -211,12 +218,14 @@ opts_data = { -h, --help Print this help message -b, --buf-keypress Use buffered keypresses as with real human input -d, --debug Produce debugging output --D, --direct-exec Bypass pexpect and execute a command directly (for debugging only) +-D, --direct-exec Bypass pexpect and execute a command directly (for + debugging only) -e, --exact-output Show the exact output of the MMGen script(s) being run -l, --list-cmds List and describe the tests and commands in the test suite -p, --pause Pause between tests, resuming on keypress -q, --quiet Produce minimal output. Suppress dependency info --s, --system Test scripts and modules installed on system rather than those in the repo root +-s, --system Test scripts and modules installed on system rather than + those in the repo root -v, --verbose Produce more verbose output """, 'notes': """ @@ -517,10 +526,6 @@ def do_between(): sys.stderr.write("\n") -hincog_bytes = 1024*1024 -hincog_offset = 98765 -hincog_seedlen = 256 - rebuild_list = OrderedDict() def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False): @@ -529,7 +534,8 @@ def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False) fns = [] if force_delete or not root: - ret = ts.get_num_exts_for_cmd(cmd,dpy) #does cmd produce a needed dependency? + # does cmd produce a needed dependency(ies)? + ret = ts.get_num_exts_for_cmd(cmd,dpy) if ret: for ext in ret[1]: fn = get_file_with_ext(ext,cfgs[ret[0]]['tmpdir'],delete=build) @@ -574,7 +580,7 @@ Fatal error - %s '%s' does not match reference value '%s'. Aborting test """.strip() % (what,chk,refchk))) sys.exit(3) -def check_deps(ts,name,cmds): +def check_deps(cmds): if len(cmds) != 1: msg("Usage: %s check_deps " % g.prog_name) sys.exit(1) @@ -624,8 +630,8 @@ class MMGenTestSuite(object): dgl = cfgs[num]['dep_generators'] # msgrepr(num,cmd,dgl) if cmd in dgl.values(): - ext = [k for k in dgl if dgl[k] == cmd][0] - return (num,[ext]) + exts = [k for k in dgl if dgl[k] == cmd] + return (num,exts) else: return None @@ -860,7 +866,8 @@ class MMGenTestSuite(object): t = MMGenExpect(name,"mmgen-walletchk",args+["-d",cfg['tmpdir'],"-r","10",walletfile]) t.passphrase("MMGen wallet",cfg['wpasswd']) t.usr_rand(10) - t.expect_getend("Incog ID: ") + incog_id = t.expect_getend("Incog ID: ") + write_to_tmpfile(cfg,incog_id_fn,incog_id+"\n") if args[0] == "-G": return t t.written_to_file("Incognito wallet data",overwrite_unlikely=True) ok() @@ -1037,7 +1044,6 @@ class MMGenTestSuite(object): write_to_file(infn,cfg['tool_enc_reftext'],silent=True) self.tool_encrypt(name,infn) - # Two deps produced by one prog is broken - TODO def tool_decrypt(self,name,f1,f2): of = name + ".out" t = MMGenExpect(name,"mmgen-tool", @@ -1051,6 +1057,14 @@ class MMGenTestSuite(object): def tool_decrypt_ref(self,name,f1,f2): self.tool_decrypt(name,f1,f2) + def tool_find_incog_data(self,name,f1,f2): + i_id = read_from_file(f2).rstrip() + vmsg("Incog ID: %s" % cyan(i_id)) + t = MMGenExpect(name,"mmgen-tool", + ["-d",cfg['tmpdir'],"find_incog_data",f1,i_id]) + o = t.expect_getend("Incog data for ID \w{8} found at offset ",regex=True) + cmp_or_die(hincog_offset,int(o)) + # main() if opt.pause: import termios,atexit diff --git a/test/tooltest.py b/test/tooltest.py index 1ed5eb7a..70c088dc 100755 --- a/test/tooltest.py +++ b/test/tooltest.py @@ -81,7 +81,8 @@ opts_data = { -h, --help Print this help message -d, --debug Produce debugging output -l, --list-cmds List and describe the tests and commands in the test suite --s, --system Test scripts and modules installed on system rather than those in the repo root +-s, --system Test scripts and modules installed on system rather than + those in the repo root -v, --verbose Produce more verbose output """, 'notes': """