Browse Source

New test 'test/gentest.py' checks MMGen's internally generated addresses
against output of 'keyconv'

New test in 'test/test.py': 'tool_find_incog_data'

philemon 10 years ago
parent
commit
d966956ffd
4 changed files with 110 additions and 18 deletions
  1. 2 2
      mmgen/addr.py
  2. 77 0
      test/gentest.py
  3. 29 15
      test/test.py
  4. 2 1
      test/tooltest.py

+ 2 - 2
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

+ 77 - 0
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"))

+ 29 - 15
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 <command>" % 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

+ 2 - 1
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': """