|
@@ -16,6 +16,8 @@ cmd_data = OrderedDict([
|
|
|
# test description depends
|
|
|
['walletgen', (1,'wallet generation', [[[],1]])],
|
|
|
['walletchk', (1,'wallet check', [[["mmdat"],1]])],
|
|
|
+ ['passchg', (5,'password, label and hash preset change',[[["mmdat"],1]])],
|
|
|
+ ['walletchk_newpass',(5,'wallet check with new pw, label and hash preset',[[["mmdat"],5]])],
|
|
|
['addrgen', (1,'address generation', [[["mmdat"],1]])],
|
|
|
['addrimport', (1,'address import', [[["addrs"],1]])],
|
|
|
['txcreate', (1,'transaction creation', [[["addrs"],1]])],
|
|
@@ -51,12 +53,12 @@ cmd_data = OrderedDict([
|
|
|
['walletgen4',(4,'wallet generation (4) (brainwallet)', [])],
|
|
|
['addrgen4', (4,'address generation (4)', [[["mmdat"],4]])],
|
|
|
['txcreate4', (4,'tx creation with inputs and outputs from four seed sources, plus non-MMGen inputs and outputs', [[["addrs"],1],[["addrs"],2],[["addrs"],3],[["addrs"],4]])],
|
|
|
- ['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet and brainwallet, plus non-MMGen inputs and outputs', [[["mmincog"],1],[["mmwords"],2],[["mmdat"],3],[["mmbrain","raw",non_mmgen_fn],4]])],
|
|
|
+ ['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet and brainwallet, plus non-MMGen inputs and outputs', [[["mmincog"],1],[["mmwords"],2],[["mmdat"],3],[["mmbrain","raw"],4]])],
|
|
|
])
|
|
|
|
|
|
utils = {
|
|
|
- 'check_deps': 'check dependencies for specified command, deleting out-of-date files',
|
|
|
- 'clean': 'clean specified tmp dir(s) (1,2,3,4; no arg = all tmpdirs)',
|
|
|
+ 'check_deps': 'check dependencies for specified command',
|
|
|
+ 'clean': 'clean specified tmp dir(s) 1, 2, 3 or 4 (no arg = all dirs)',
|
|
|
}
|
|
|
|
|
|
addrs_per_wallet = 8
|
|
@@ -112,19 +114,29 @@ cfgs = {
|
|
|
'addrs': "addrgen4",
|
|
|
'raw': "txcreate4",
|
|
|
'sig': "txsign4",
|
|
|
- non_mmgen_fn: "txcreate4"
|
|
|
},
|
|
|
'bw_filename': "brainwallet.mmbrain",
|
|
|
'bw_params': "256,1",
|
|
|
},
|
|
|
+ '5': {
|
|
|
+ 'tmpdir': "test/tmp5",
|
|
|
+ 'wpasswd': "My changed password",
|
|
|
+ 'dep_generators': {
|
|
|
+ 'mmdat': "passchg",
|
|
|
+ },
|
|
|
+ },
|
|
|
}
|
|
|
-cfg = cfgs['1']
|
|
|
|
|
|
from binascii import hexlify
|
|
|
def getrand(n): return int(hexlify(os.urandom(n)),16)
|
|
|
-def msgrepr(d): sys.stderr.write(repr(d)+"\n")
|
|
|
-def msgrepr_exit(d):
|
|
|
- sys.stderr.write(repr(d)+"\n")
|
|
|
+
|
|
|
+def msgrepr(*args):
|
|
|
+ for d in args:
|
|
|
+ sys.stdout.write(repr(d)+"\n")
|
|
|
+
|
|
|
+def msgrepr_exit(*args):
|
|
|
+ for d in args:
|
|
|
+ sys.stdout.write(repr(d)+"\n")
|
|
|
sys.exit()
|
|
|
|
|
|
# total of two outputs must be < 10 BTC
|
|
@@ -135,6 +147,7 @@ for k in cfgs.keys():
|
|
|
|
|
|
meta_cmds = OrderedDict([
|
|
|
['gen', (1,("walletgen","walletchk","addrgen"))],
|
|
|
+ ['pass', (5,("passchg","walletchk_newpass"))],
|
|
|
['tx', (1,("txcreate","txsign","txsend"))],
|
|
|
['export', (1,[k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1])],
|
|
|
['gen_sp', (1,[k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1])],
|
|
@@ -278,19 +291,18 @@ def cleandir(d):
|
|
|
for f in files:
|
|
|
os.unlink(os.path.join(d,f))
|
|
|
|
|
|
-def get_file_with_ext(ext,mydir,delete=False):
|
|
|
- flist = [os.path.join(mydir,f)
|
|
|
- for f in os.listdir(mydir) if f.split(".")[-1] == ext]
|
|
|
- if not flist:
|
|
|
- flist = [os.path.join(mydir,f)
|
|
|
- for f in os.listdir(mydir) if ".".join(f.split(".")[-2:]) == ext]
|
|
|
- if not flist:
|
|
|
- return False
|
|
|
+def get_file_with_ext(ext,mydir,delete=True):
|
|
|
|
|
|
- if len(flist) > 1 or delete:
|
|
|
- if not quiet:
|
|
|
- msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
|
|
|
- for f in flist: os.unlink(f)
|
|
|
+ flist = [os.path.join(mydir,f) for f in os.listdir(mydir)
|
|
|
+ if f == ext or f[-(len(ext)+1):] == "."+ext]
|
|
|
+
|
|
|
+ if not flist: return False
|
|
|
+
|
|
|
+ if len(flist) > 1:
|
|
|
+ if delete:
|
|
|
+ if not quiet:
|
|
|
+ msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
|
|
|
+ for f in flist: os.unlink(f)
|
|
|
return False
|
|
|
else:
|
|
|
return flist[0]
|
|
@@ -323,6 +335,7 @@ class MMGenExpect(object):
|
|
|
)
|
|
|
else:
|
|
|
msg_r("Testing %s " % (desc+":"))
|
|
|
+# msgrepr(mmgen_cmd,cmd_args); msg("")
|
|
|
if env: self.p = pexpect.spawn(mmgen_cmd,cmd_args,env=env)
|
|
|
else: self.p = pexpect.spawn(mmgen_cmd,cmd_args)
|
|
|
if exact_output: self.p.logfile = sys.stdout
|
|
@@ -348,8 +361,9 @@ class MMGenExpect(object):
|
|
|
my_expect(self.p,("Enter passphrase for new %s: " % what), passphrase+"\n")
|
|
|
my_expect(self.p,"Repeat passphrase: ", passphrase+"\n")
|
|
|
|
|
|
- def passphrase(self,what,passphrase):
|
|
|
- my_expect(self.p,("Enter passphrase for %s.*?: " % what),
|
|
|
+ def passphrase(self,what,passphrase,pwtype=""):
|
|
|
+ if pwtype: pwtype += " "
|
|
|
+ my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,what)),
|
|
|
passphrase+"\n",regex=True)
|
|
|
|
|
|
def hash_preset(self,what,preset=''):
|
|
@@ -486,53 +500,73 @@ def do_between():
|
|
|
|
|
|
def do_cmd(ts,cmd):
|
|
|
|
|
|
- al = []
|
|
|
- for exts,idx in cmd_data[cmd][2]:
|
|
|
- global cfg
|
|
|
- cfg = cfgs[str(idx)]
|
|
|
- for ext in exts:
|
|
|
- while True:
|
|
|
- infile = get_file_with_ext(ext,cfg['tmpdir'])
|
|
|
- if infile:
|
|
|
- al.append(infile); break
|
|
|
- else:
|
|
|
- dg = cfg['dep_generators'][ext]
|
|
|
- if not quiet: msg("Need *.%s from '%s'" % (ext,dg))
|
|
|
- do_cmd(ts,dg)
|
|
|
- do_between()
|
|
|
+ d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
|
|
|
+ al = [get_file_with_ext(ext,cfgs[num]['tmpdir']) for num,ext in d]
|
|
|
+
|
|
|
+ global cfg
|
|
|
+ cfg = cfgs[str(cmd_data[cmd][0])]
|
|
|
|
|
|
MMGenTestSuite.__dict__[cmd](*([ts,cmd] + al))
|
|
|
|
|
|
+
|
|
|
hincog_bytes = 1024*1024
|
|
|
hincog_offset = 98765
|
|
|
hincog_seedlen = 256
|
|
|
|
|
|
rebuild_list = OrderedDict()
|
|
|
|
|
|
-def check_if_needs_rebuild(num,ext):
|
|
|
- ret = False
|
|
|
+def get_num_ext_for_cmd(cmd):
|
|
|
+ num = str(cmd_data[cmd][0])
|
|
|
+ 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)
|
|
|
+ else:
|
|
|
+ return ('','')
|
|
|
+
|
|
|
+def check_needs_rerun(cmd,build=False,root=True,force_delete=False):
|
|
|
|
|
|
- fn = get_file_with_ext(ext,cfgs[num]['tmpdir'])
|
|
|
- if not fn: ret = True
|
|
|
+ rerun = True if root else False
|
|
|
|
|
|
- cmd = cfgs[num]['dep_generators'][ext]
|
|
|
- deps = [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
|
|
|
+ num,ext = get_num_ext_for_cmd(cmd) # does cmd produce a needed dependency?
|
|
|
+ if num and (force_delete or not root):
|
|
|
+ fn = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
|
|
|
+ if not fn: rerun = True
|
|
|
+ if fn and force_delete:
|
|
|
+ os.unlink(fn); fn = ""
|
|
|
+ else: fn = ""
|
|
|
+
|
|
|
+ fdeps = [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
|
|
|
+ cdeps = [cfgs[str(n)]['dep_generators'][e] for n,e in fdeps]
|
|
|
|
|
|
if fn:
|
|
|
my_age = os.stat(fn).st_mtime
|
|
|
- for num,ext in deps:
|
|
|
- f = get_file_with_ext(ext,cfgs[num]['tmpdir'])
|
|
|
- if f and os.stat(f).st_mtime > my_age: ret = True
|
|
|
+ for num,ext in fdeps:
|
|
|
+ f = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
|
|
|
+ if f and os.stat(f).st_mtime > my_age: rerun = True
|
|
|
+
|
|
|
+ for cdep in cdeps:
|
|
|
+ if check_needs_rerun(cdep,build=build,root=False): rerun = True
|
|
|
|
|
|
- for num,ext in deps:
|
|
|
- if check_if_needs_rebuild(num,ext): ret = True
|
|
|
+ if build:
|
|
|
+ if rerun:
|
|
|
+ if fn and not root:
|
|
|
+ os.unlink(fn)
|
|
|
+ do_cmd(ts,cmd)
|
|
|
+ if not root: do_between()
|
|
|
+ else:
|
|
|
+ # If prog produces multiple files:
|
|
|
+ if cmd not in rebuild_list or rerun == True:
|
|
|
+ rebuild_list[cmd] = (rerun,fn)
|
|
|
|
|
|
- if ret and fn:
|
|
|
- if not quiet: msg("File '%s' out of date - deleting" % fn)
|
|
|
- os.unlink(fn)
|
|
|
+ return rerun
|
|
|
|
|
|
- rebuild_list[cmd] = ret
|
|
|
- return ret
|
|
|
+def mk_tmpdir(cfg):
|
|
|
+ try: os.mkdir(cfg['tmpdir'],0755)
|
|
|
+ except OSError as e:
|
|
|
+ if e.errno != 17: raise
|
|
|
+ else: msg("Created directory '%s'" % cfg['tmpdir'])
|
|
|
|
|
|
|
|
|
class MMGenTestSuite(object):
|
|
@@ -551,19 +585,17 @@ class MMGenTestSuite(object):
|
|
|
msg("'%s': unrecognized command" % cmd)
|
|
|
sys.exit(1)
|
|
|
|
|
|
- d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
|
|
|
-
|
|
|
if not quiet:
|
|
|
- w = "Checking" if d else "No"
|
|
|
- msg("%s dependencies for '%s'" % (w,cmd))
|
|
|
+ msg("Checking dependencies for '%s'" % (cmd))
|
|
|
|
|
|
- for num,ext in d:
|
|
|
- check_if_needs_rebuild(num,ext)
|
|
|
+ check_needs_rerun(cmd,build=False)
|
|
|
|
|
|
- if debug:
|
|
|
- for cmd in rebuild_list:
|
|
|
- msg("cmd: %-15s rebuild: %s" %
|
|
|
- (cmd, cyan("Yes") if rebuild_list[cmd] else "No"))
|
|
|
+ w = max(len(i) for i in rebuild_list) + 1
|
|
|
+ for cmd in rebuild_list:
|
|
|
+ c = rebuild_list[cmd]
|
|
|
+ m = "Rebuild" if (c[0] and c[1]) else "Build" if c[0] else "OK"
|
|
|
+ msg("cmd {:<{w}} {}".format(cmd+":", m, w=w))
|
|
|
+# msgrepr(cmd,c)
|
|
|
|
|
|
|
|
|
def clean(self,name,dirs=[]):
|
|
@@ -576,11 +608,7 @@ class MMGenTestSuite(object):
|
|
|
sys.exit(1)
|
|
|
|
|
|
def walletgen(self,name,brain=False):
|
|
|
- try: os.mkdir(cfg['tmpdir'],0755)
|
|
|
- except OSError as e:
|
|
|
- if e.errno != 17: raise
|
|
|
- else: msg("Created directory '%s'" % cfg['tmpdir'])
|
|
|
- # cleandir(cfg['tmpdir'])
|
|
|
+ mk_tmpdir(cfg)
|
|
|
|
|
|
args = ["-d",cfg['tmpdir'],"-p1","-r10"]
|
|
|
if brain:
|
|
@@ -606,6 +634,25 @@ class MMGenTestSuite(object):
|
|
|
t.written_to_file("Wallet")
|
|
|
t.ok()
|
|
|
|
|
|
+ def passchg(self,name,walletfile):
|
|
|
+ mk_tmpdir(cfg)
|
|
|
+
|
|
|
+ t = MMGenExpect(name,"mmgen-passchg",
|
|
|
+ ["-d",cfg['tmpdir'],"-p","2","-L","New Label","-r","16",walletfile])
|
|
|
+ t.passphrase("MMGen wallet",cfgs['1']['wpasswd'],pwtype="old")
|
|
|
+ t.expect_getend("Label changed: ")
|
|
|
+ t.expect_getend("Hash preset has changed ")
|
|
|
+ t.passphrase("MMGen wallet",cfg['wpasswd'],pwtype="new")
|
|
|
+ t.expect("Repeat passphrase: ",cfg['wpasswd']+"\n")
|
|
|
+ t.usr_rand(16)
|
|
|
+ t.expect_getend("Key ID changed: ")
|
|
|
+ t.written_to_file("Wallet")
|
|
|
+ t.ok()
|
|
|
+
|
|
|
+ def walletchk_newpass(self,name,walletfile):
|
|
|
+ t = self.walletchk_beg(name,[walletfile])
|
|
|
+ t.ok()
|
|
|
+
|
|
|
def walletchk_beg(self,name,args):
|
|
|
t = MMGenExpect(name,"mmgen-walletchk", args)
|
|
|
t.expect("Getting MMGen wallet data from file '%s'" % args[-1])
|
|
@@ -838,8 +885,6 @@ class MMGenTestSuite(object):
|
|
|
t.ok()
|
|
|
|
|
|
def walletgen2(self,name):
|
|
|
- global cfg
|
|
|
- cfg = cfgs['2']
|
|
|
self.walletgen(name)
|
|
|
|
|
|
def addrgen2(self,name,walletfile):
|
|
@@ -865,8 +910,6 @@ class MMGenTestSuite(object):
|
|
|
self.export_mnemonic(name,walletfile)
|
|
|
|
|
|
def walletgen3(self,name):
|
|
|
- global cfg
|
|
|
- cfg = cfgs['3']
|
|
|
self.walletgen(name)
|
|
|
|
|
|
def addrgen3(self,name,walletfile):
|
|
@@ -890,8 +933,6 @@ class MMGenTestSuite(object):
|
|
|
t.ok()
|
|
|
|
|
|
def walletgen4(self,name):
|
|
|
- global cfg
|
|
|
- cfg = cfgs['4']
|
|
|
self.walletgen(name,brain=True)
|
|
|
|
|
|
def addrgen4(self,name,walletfile):
|
|
@@ -900,7 +941,8 @@ class MMGenTestSuite(object):
|
|
|
def txcreate4(self,name,f1,f2,f3,f4):
|
|
|
self.txcreate_common(name,sources=['1','2','3','4'],non_mmgen_input='4')
|
|
|
|
|
|
- def txsign4(self,name,f1,f2,f3,f4,f5,non_mm_fn):
|
|
|
+ def txsign4(self,name,f1,f2,f3,f4,f5):
|
|
|
+ non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
|
|
|
t = MMGenExpect(name,"mmgen-txsign",
|
|
|
["-d",cfg['tmpdir'],"-b",cfg['bw_params'],"-k",non_mm_fn,f1,f2,f3,f4,f5])
|
|
|
t.license()
|
|
@@ -933,22 +975,18 @@ try:
|
|
|
if cmd_args:
|
|
|
arg1 = cmd_args[0]
|
|
|
if arg1 in utils:
|
|
|
- if arg1 == "check_deps": debug = True
|
|
|
MMGenTestSuite.__dict__[arg1](ts,arg1,cmd_args[1:])
|
|
|
sys.exit()
|
|
|
elif arg1 in meta_cmds:
|
|
|
if len(cmd_args) == 1:
|
|
|
- ts.clean("clean",str(meta_cmds[arg1][0]))
|
|
|
for cmd in meta_cmds[arg1][1]:
|
|
|
- do_cmd(ts,cmd)
|
|
|
- if cmd is not cmd_data.keys()[-1]: do_between()
|
|
|
+ check_needs_rerun(cmd,build=True,force_delete=True)
|
|
|
else:
|
|
|
msg("Only one meta command may be specified")
|
|
|
sys.exit(1)
|
|
|
elif arg1 in cmd_data:
|
|
|
if len(cmd_args) == 1:
|
|
|
- ts.check_deps("check_deps",[arg1])
|
|
|
- do_cmd(ts,arg1)
|
|
|
+ check_needs_rerun(arg1,build=True)
|
|
|
else:
|
|
|
msg("Only one command may be specified")
|
|
|
sys.exit(1)
|