From 4a93cdee6a10ddd69555844cd651d3fbc04332b2 Mon Sep 17 00:00:00 2001 From: philemon Date: Tue, 7 Apr 2015 17:57:17 +0300 Subject: [PATCH] test/test.py: To make sure backwards compatibility is maintained, added reference files and tests for all MMGen wallet formats, tx, address and key-address files. --- mmgen/addr.py | 64 +-- mmgen/config.py | 15 +- mmgen/crypto.py | 15 +- mmgen/filename.py | 2 +- mmgen/license.py | 4 +- mmgen/main_addrgen.py | 27 +- mmgen/main_addrimport.py | 8 +- mmgen/main_passchg.py | 14 +- mmgen/main_tool.py | 5 +- mmgen/main_txcreate.py | 33 +- mmgen/main_txsend.py | 3 +- mmgen/main_txsign.py | 64 +-- mmgen/main_walletchk.py | 10 +- mmgen/main_walletgen.py | 21 +- mmgen/mn_electrum.py | 2 +- mmgen/opts.py | 9 +- mmgen/seed.py | 12 +- mmgen/test.py | 7 +- mmgen/tool.py | 12 +- mmgen/tx.py | 27 +- mmgen/util.py | 6 +- test/ref/1378FC64-6F0F9BB4[192,1].mmdat | 6 + ...4-B55E9958-77256FC1[192:1].incog.offset123 | Bin 0 -> 1024 bytes ...5E9958-D85FF20C[192:1].incog-old.offset123 | Bin 0 -> 1024 bytes test/ref/1378FC64.mmseed | 1 + test/ref/1378FC64.mmwords | 1 + test/ref/98831F3A-27F2BF93[256,1].mmdat | 6 + ...A-F59B07A0-559CEF19[256:1].incog.offset123 | Bin 0 -> 1024 bytes ...9B07A0-848535F3[256:1].incog-old.offset123 | Bin 0 -> 1024 bytes test/ref/98831F3A.mmseed | 1 + test/ref/98831F3A.mmwords | 1 + .../98831F3A[1,31-33,500-501,1010-1011].addrs | 19 + ...F3A[1,31-33,500-501,1010-1011].akeys.mmenc | Bin 0 -> 1454 bytes ...1E495F-9860A85B[128:1].incog-old.offset123 | 6 + ...5-161E495F-BEB7548E[128:1].incog-offset123 | Bin 0 -> 1024 bytes test/ref/FE3C6545-D782B529[128,1].mmdat | 6 + test/ref/FE3C6545.mmseed | 1 + test/ref/FE3C6545.mmwords | 1 + test/ref/brainwallet | 1 + test/ref/brainwallet-spaced | 11 + test/ref/tx_FFB367[1.234].raw | 5 + test/test.py | 404 +++++++++++++----- 42 files changed, 562 insertions(+), 268 deletions(-) create mode 100644 test/ref/1378FC64-6F0F9BB4[192,1].mmdat create mode 100644 test/ref/1378FC64-B55E9958-77256FC1[192:1].incog.offset123 create mode 100644 test/ref/1378FC64-B55E9958-D85FF20C[192:1].incog-old.offset123 create mode 100644 test/ref/1378FC64.mmseed create mode 100644 test/ref/1378FC64.mmwords create mode 100644 test/ref/98831F3A-27F2BF93[256,1].mmdat create mode 100644 test/ref/98831F3A-F59B07A0-559CEF19[256:1].incog.offset123 create mode 100644 test/ref/98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123 create mode 100644 test/ref/98831F3A.mmseed create mode 100644 test/ref/98831F3A.mmwords create mode 100644 test/ref/98831F3A[1,31-33,500-501,1010-1011].addrs create mode 100644 test/ref/98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc create mode 100644 test/ref/FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123 create mode 100644 test/ref/FE3C6545-161E495F-BEB7548E[128:1].incog-offset123 create mode 100644 test/ref/FE3C6545-D782B529[128,1].mmdat create mode 100644 test/ref/FE3C6545.mmseed create mode 100644 test/ref/FE3C6545.mmwords create mode 100644 test/ref/brainwallet create mode 100644 test/ref/brainwallet-spaced create mode 100644 test/ref/tx_FFB367[1.234].raw diff --git a/mmgen/addr.py b/mmgen/addr.py index b0a2e092..508d04ad 100755 --- a/mmgen/addr.py +++ b/mmgen/addr.py @@ -29,24 +29,27 @@ from mmgen.bitcoin import numtowif # from mmgen.util import msg,qmsg,qmsg_r,make_chksum_N,get_lines_from_file,get_data_from_file,get_extension from mmgen.util import * from mmgen.tx import * +from mmgen.obj import * import mmgen.config as g import mmgen.opt as opt +pnm = g.proj_name + addrmsgs = { 'addrfile_header': """ -# MMGen address file +# {pnm} address file # # This file is editable. # Everything following a hash symbol '#' is a comment and ignored by {pnm}. -# A text label of {} characters or less may be added to the right of each +# A text label of {n} characters or less may be added to the right of each # address, and it will be appended to the bitcoind wallet label upon import. # The label may contain any printable ASCII symbol. -""".strip().format(g.max_addr_label_len,pnm=g.proj_name), +""".strip().format(n=g.max_addr_label_len,pnm=pnm), 'no_keyconv_msg': """ -Executable '{kcexe}' unavailable. Falling back on (slow) internal ECDSA library. -Please install '{kcexe}' from the {vanityg} package on your system for much +Executable '{kconv}' unavailable. Falling back on (slow) internal ECDSA library. +Please install '{kconv}' from the {vgen} package on your system for much faster address generation. -""".format(kcexe=g.keyconv_exec, vanityg="vanitygen") +""".format(kconv=g.keyconv_exec, vgen="vanitygen") } def test_for_keyconv(silent=False): @@ -61,7 +64,7 @@ def test_for_keyconv(silent=False): return True -def generate_addrs(seed, addrnums): +def generate_addrs(seed, addrnums, source="addrgen"): from util import make_chksum_8 seed_id = make_chksum_8(seed) # Must do this before seed gets clobbered @@ -116,7 +119,7 @@ def generate_addrs(seed, addrnums): m = w[0] if t_addrs == 1 else w[0]+w[1] qmsg("\r%s: %s %s generated%s" % (seed_id,t_addrs,m," "*15)) - a = AddrInfo(has_keys='k' in opt.gen_what) + a = AddrInfo(has_keys='k' in opt.gen_what, source=source) a.initialize(seed_id,out) return a @@ -182,7 +185,7 @@ def _parse_addrfile(fn,buf=[],has_keys=False,exit_on_error=True): elif cbrace != '}': errmsg = "'%s': invalid last line" % cbrace elif not is_mmgen_seed_id(sid): - errmsg = "'%s': invalid Seed ID" % sid + errmsg = "'%s': invalid seed ID" % sid else: ret = _parse_addrfile_body(lines[1:-1],has_keys) if type(ret) == list: return sid,ret @@ -196,7 +199,7 @@ def _parse_addrfile(fn,buf=[],has_keys=False,exit_on_error=True): def _parse_keyaddr_file(infile): - d = get_data_from_file(infile,"%s key-address file data" % g.proj_name) + d = get_data_from_file(infile,"{pnm} key-address file data".format(pnm=pnm)) enc_ext = get_extension(infile) == g.mmenc_ext if enc_ext or not is_utf8(d): m = "Decrypting" if enc_ext else "Attempting to decrypt" @@ -206,7 +209,7 @@ def _parse_keyaddr_file(infile): return _parse_addrfile("",buf=d,has_keys=True,exit_on_error=False) -class AddrInfoList(object): +class AddrInfoList(MMGenObject): def __init__(self,addrinfo=None,bitcoind_connection=None): self.data = {} @@ -239,7 +242,8 @@ class AddrInfoList(object): a.idx,a.addr,a.comment = \ int(idx),unicode(addrlist[0]),unicode(comment) data[seed_id].append(a) - vmsg("%s %s addresses found, %s accounts total" % (i,g.proj_name,len(accts))) + vmsg("{n} {pnm} addresses found, {m} accounts total".format( + n=i,pnm=pnm,m=len(accts))) for sid in data: self.add(AddrInfo(sid=sid,adata=data[sid])) @@ -257,22 +261,25 @@ class AddrInfoList(object): d.update(self.data[k].make_reverse_dict(btcaddrs)) return d -class AddrInfoEntry(object): +class AddrInfoEntry(MMGenObject): def __init__(self): pass -class AddrInfo(object): +class AddrInfo(MMGenObject): - def __init__(self,addrfile="",has_keys=False,sid="",adata=[]): - self.has_keys=has_keys + def __init__(self,addrfile="",has_keys=False,sid="",adata=[], source=""): + self.has_keys = has_keys + do_chksum = True if addrfile: f = _parse_keyaddr_file if has_keys else _parse_addrfile sid,adata = f(addrfile) + self.source = "addrfile" elif sid and adata: # data from wallet - pass + self.source = "wallet" elif sid or adata: die(3,"Must specify address file, or seed_id + adata") else: + self.source = source if source else "unknown" return self.initialize(sid,adata) @@ -284,12 +291,21 @@ class AddrInfo(object): self.seed_id = seed_id self.addrdata = addrdata self.num_addrs = len(addrdata) - self.make_addrdata_chksum() - self.fmt_addr_idxs() - w = "key" if self.has_keys else "addr" - qmsg("Computed checksum for %s data %s[%s]: %s" % - (w,self.seed_id,self.idxs_fmt,self.checksum)) - qmsg("Check this value against your records") + if self.source in ("wallet","txsign") or \ + (self.source == "addrgen" and opt.gen_what == "k"): + self.checksum = None + self.idxs_fmt = None + else: # self.source in addrfile, addrgen + self.make_addrdata_chksum() + self.fmt_addr_idxs() + w = "key-address" if self.has_keys else "address" + qmsg("Checksum for %s data %s[%s]: %s" % + (w,self.seed_id,self.idxs_fmt,self.checksum)) + if self.source == "addrgen": + qmsg( + "This checksum will be used to verify the address file in the future") + elif self.source == "addrfile": + qmsg("Check this value against your records") def idxs(self): return [e.idx for e in self.addrdata] @@ -337,7 +353,7 @@ class AddrInfo(object): def make_addrdata_chksum(self): nchars = 24 - lines = [" ".join([str(e.idx),e.addr]+([e.wif] if self.has_keys else [])) + lines=[" ".join([str(e.idx),e.addr]+([e.wif] if self.has_keys else [])) for e in self.addrdata] self.checksum = make_chksum_N(" ".join(lines), nchars, sep=True) diff --git a/mmgen/config.py b/mmgen/config.py index 109f9283..d6cae1ab 100755 --- a/mmgen/config.py +++ b/mmgen/config.py @@ -56,7 +56,6 @@ required_opts = [ "usr_randchars","stdout","show_hash_presets" ] min_screen_width = 80 -max_tx_comment_len = 72 wallet_ext = "mmdat" seed_ext = "mmseed" @@ -84,12 +83,11 @@ default_wordlist = "electrum" dfl_vars = "seed_len","hash_preset","usr_randchars","debug" seed_lens = 128,192,256 - mn_lens = [i / 32 * 3 for i in seed_lens] keyconv_exec = "keyconv" -mins_per_block = 8.5 +mins_per_block = 9 passwd_max_tries = 5 max_urandchars,min_urandchars = 80,10 @@ -113,16 +111,15 @@ hash_presets = { mmgen_idx_max_digits = 7 -from string import ascii_letters, digits +printable_nonl = [chr(i+32) for i in range(95)] +printable = printable_nonl + ['\n','\t'] + +addr_label_symbols = wallet_label_symbols = printable_nonl -addr_label_symbols = tuple([chr(i) for i in range(0x20,0x7f)]) max_addr_label_len = 32 - -wallet_label_symbols = addr_label_symbols max_wallet_label_len = 48 +max_tx_comment_len = 72 # Comment is b58 encoded, so can permit all UTF-8 -printable_nospc = [chr(i+33) for i in range(94)] -printable = printable_nospc + [' ','\n','\t'] #addr_label_punc = ".","_",",","-"," ","(",")" #addr_label_symbols = tuple(ascii_letters + digits) + addr_label_punc #wallet_label_punc = addr_label_punc diff --git a/mmgen/crypto.py b/mmgen/crypto.py index 5306454c..b246c79b 100755 --- a/mmgen/crypto.py +++ b/mmgen/crypto.py @@ -218,7 +218,7 @@ def get_random(length): def get_seed_from_wallet( infile, - prompt_info="{} wallet".format(g.proj_name), + prompt_info="{pnm} wallet".format(pnm=g.proj_name), silent=False ): @@ -270,7 +270,7 @@ def confirm_old_format(): def get_seed_from_incog_wallet( infile, - prompt_info="{} incognito wallet".format(g.proj_name), + prompt_info="{pnm} incognito wallet".format(pnm=g.proj_name), silent=False, hex_input=False ): @@ -305,7 +305,7 @@ def get_seed_from_incog_wallet( incog_id = make_iv_chksum(iv) msg("Incog ID: %s (IV ID: %s)" % (incog_id,make_chksum_8(iv))) - qmsg("Check the applicable value against your records.") + qmsg("Check the applicable value against your records") vmsg(crmsg['incog_iv_id_hidden' if opt.from_incog_hidden else 'incog_iv_id']) @@ -328,7 +328,7 @@ def get_seed_from_incog_wallet( old_fmt_sid = make_chksum_8(seed) def confirm_correct_seed_id(sid): - m = "Seed ID: %s. Is the Seed ID correct?" % sid + m = "Seed ID: %s. Is the seed ID correct?" % sid return keypress_confirm(m, True) if opt.old_incog_fmt: @@ -344,6 +344,7 @@ def get_seed_from_incog_wallet( if confirm_correct_seed_id(old_fmt_sid): break + msg("Valid incog data for seed ID %s" % make_chksum_8(seed)) return seed @@ -412,7 +413,7 @@ def get_seed_retry(infile,seed_id=""): if seed: return seed -def _get_seed_from_brain_passphrase(words): +def _get_seed_from_brain_passphrase(words,silent=False): bp = " ".join(words) if opt.debug: Msg("Sanitized brain passphrase: %s" % bp) seed_len,hash_preset = get_from_brain_opt_params() @@ -421,6 +422,10 @@ def _get_seed_from_brain_passphrase(words): # Use buflen arg of scrypt.hash() to get seed of desired length seed = scrypt_hash_passphrase(bp, "", hash_preset, buflen=seed_len/8) vmsg("Done") + + if not silent: + msg("Valid brainwallet for seed ID %s" % make_chksum_8(seed)) + return seed diff --git a/mmgen/filename.py b/mmgen/filename.py index 5f77f84a..a535858d 100755 --- a/mmgen/filename.py +++ b/mmgen/filename.py @@ -20,7 +20,7 @@ filename.py: Filename class and methods for the MMGen suite """ import sys,os -from mmgen.obj import MMGenObject +from mmgen.obj import * import mmgen.config as g from mmgen.util import msg diff --git a/mmgen/license.py b/mmgen/license.py index 61859b7b..ce4898c9 100755 --- a/mmgen/license.py +++ b/mmgen/license.py @@ -23,10 +23,10 @@ import mmgen.config as g gpl = { 'warning': """ - MMGen Copyright (C) {g.Cdates} by {g.author} {g.email}. This + {pnm} Copyright (C) {g.Cdates} by {g.author} {g.email}. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. -""".format(g=g), +""".format(g=g,pnm=g.proj_name), 'prompt': """ Press 'w' for conditions and warranty info, or 'c' to continue: """, diff --git a/mmgen/main_addrgen.py b/mmgen/main_addrgen.py index 6e1725af..ec985d99 100755 --- a/mmgen/main_addrgen.py +++ b/mmgen/main_addrgen.py @@ -32,8 +32,8 @@ from mmgen.addr import * what = "keys" if sys.argv[0].split("-")[-1] == "keygen" else "addresses" opts_data = { - 'desc': """Generate a range or list of {} from an {g.proj_name} wallet, - mnemonic, seed or password""".format(what,g=g), + 'desc': """Generate a range or list of {w} from an {pnm} wallet, + mnemonic, seed or password""".format(w=what,pnm=g.proj_name), 'usage':"[opts] [infile]
", 'options': """ -h, --help Print this help message{} @@ -47,7 +47,7 @@ opts_data = { (default: {g.seed_len}) -p, --hash-preset= p Use scrypt.hash() parameters from preset 'p' when hashing password (default: '{g.hash_preset}') --P, --passwd-file= f Get MMGen wallet passphrase from file 'f' +-P, --passwd-file= f Get {pnm} wallet passphrase from file 'f' -q, --quiet Suppress warnings; overwrite files without prompting -S, --stdout Print {what} to stdout @@ -71,7 +71,7 @@ opts_data = { ) if what == "keys" else ("","")), seed_lens=", ".join([str(i) for i in g.seed_lens]), - what=what, g=g + what=what,g=g,pnm=g.proj_name ), 'notes': """ @@ -107,9 +107,9 @@ invocations with that passphrase wmsg = { 'unencrypted_secret_keys': """ -This program generates secret keys from your {} seed, outputting them in +This program generates secret keys from your {pnm} seed, outputting them in UNENCRYPTED form. Generate only the key(s) you need and guard them carefully. -""".format(g.proj_name), +""".format(pnm=g.proj_name), } cmd_args = opt.opts.init(opts_data,add_opts=["b16"]) @@ -136,25 +136,20 @@ if what == "keys" and not opt.quiet: # Generate data: -seed = get_seed_retry(infile) +seed = get_seed_retry(infile) opt.gen_what = "a" if what == "addresses" else ( "k" if opt.no_addresses else "ka") -ainfo = generate_addrs(seed, addr_idxs) +ainfo = generate_addrs(seed,addr_idxs) addrdata_str = ainfo.fmt_data() outfile_base = "{}[{}]".format(make_chksum_8(seed), ainfo.idxs_fmt) -if 'a' in opt.gen_what: +if 'a' in opt.gen_what and opt.save_checksum: w = "key-address" if 'k' in opt.gen_what else "address" - qmsg("Checksum for %s data %s: %s" % (w,outfile_base,ainfo.checksum)) - if opt.save_checksum: - write_to_file(outfile_base+"."+g.addrfile_chksum_ext, - ainfo.checksum+"\n","%s data checksum" % w,True,True,False) - else: - qmsg("This checksum will be used to verify the %s file in the future."%w) - qmsg("Record it to a safe location.") + write_to_file(outfile_base+"."+g.addrfile_chksum_ext, + ainfo.checksum+"\n","%s data checksum" % w,True,True,False) if 'k' in opt.gen_what and keypress_confirm("Encrypt key list?"): addrdata_str = mmgen_encrypt(addrdata_str,"new key list","") diff --git a/mmgen/main_addrimport.py b/mmgen/main_addrimport.py index 0832fa25..247ad723 100755 --- a/mmgen/main_addrimport.py +++ b/mmgen/main_addrimport.py @@ -53,7 +53,7 @@ if len(cmd_args) == 1: check_infile(infile) if opt.addrlist: lines = get_lines_from_file( - infile,"non-{} addresses".format(g.proj_name),trim_comments=True) + infile,"non-{pnm} addresses".format(pnm=g.proj_name),trim_comments=True) ai,adata = AddrInfo(),[] for btcaddr in lines: a = AddrInfoEntry() @@ -64,9 +64,9 @@ if len(cmd_args) == 1: ai = AddrInfo(infile,has_keys=opt.keyaddr_file) else: msg(""" -"You must specify an mmgen address file (or a list of non-%s addresses +"You must specify an mmgen address file (or a list of non-{pnm} addresses with the '--addrlist' option) -""".strip() % g.proj_name) +""".strip().format(pnm=g.proj_name)) sys.exit(1) from mmgen.bitcoin import verify_addr @@ -124,7 +124,7 @@ for n,e in enumerate(ai.addrdata): if e.idx: label = "%s:%s" % (ai.seed_id,e.idx) if e.comment: label += " " + e.comment - else: label = "non-%s" % g.proj_name + else: label = "non-{pnm}".format(pnm=g.proj_name) if opt.rescan: t = threading.Thread(target=import_address, args=(e.addr,label,True)) diff --git a/mmgen/main_passchg.py b/mmgen/main_passchg.py index f40479a1..8ce416c5 100755 --- a/mmgen/main_passchg.py +++ b/mmgen/main_passchg.py @@ -28,8 +28,8 @@ import mmgen.config as g import mmgen.opt as opt opts_data = { - 'desc': """Change the passphrase, hash preset or label of an {} - deterministic wallet""".format(g.proj_name), + 'desc': """Change the passphrase, hash preset or label of an {pnm} + deterministic wallet""".format(pnm=g.proj_name), 'usage': "[opts] [filename]", 'options': """ -h, --help Print this help message @@ -40,13 +40,13 @@ opts_data = { -L, --label= l Change the wallet's label to 'l' -p, --hash-preset= p Change scrypt.hash() parameters to preset 'p' (default: '{g.hash_preset}') --P, --passwd-file= f Get new MMGen wallet passphrase from file 'f' +-P, --passwd-file= f Get new {pnm} wallet passphrase from file 'f' -r, --usr-randchars= n Get 'n' characters of additional randomness from user (min={g.min_urandchars}, max={g.max_urandchars}) -q, --quiet Suppress warnings; overwrite files without prompting -v, --verbose Produce more verbose output -""".format(g=g), +""".format(g=g,pnm=g.proj_name), 'notes': """ NOTE: The key ID will change if either the passphrase or hash preset are @@ -67,7 +67,7 @@ seed_id,key_id = metadata[:2] # Repeat on incorrect pw entry while True: - p = "{} wallet".format(g.proj_name) + p = "{pnm} wallet".format(pnm=g.proj_name) passwd = get_mmgen_passphrase(p,not opt.keep_old_passphrase) key = make_key(passwd, salt, hash_preset) seed = decrypt_seed(enc_seed, key, seed_id, key_id) @@ -85,7 +85,7 @@ else: opt.label = label # Copy the old label if opt.hash_preset: if hash_preset != opt.hash_preset: - qmsg("Hash preset has changed (%s -> %s)" % + qmsg("Hash preset changed: '%s' -> '%s'" % (hash_preset, opt.hash_preset)) changed['preset'] = True else: @@ -97,7 +97,7 @@ if opt.keep_old_passphrase: msg("Keeping old passphrase by user request") else: new_passwd = get_new_passphrase( - "{} wallet".format(g.proj_name), True) + "{pnm} wallet".format(pnm=g.proj_name), True) if new_passwd == passwd: qmsg("Passphrase is unchanged") diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 06520046..4828e519 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -27,7 +27,7 @@ import mmgen.opt as opt import mmgen.tool as tool opts_data = { - 'desc': "Perform various MMGen- and Bitcoin-related operations", + 'desc': "Perform various {pnm}- and Bitcoin-related operations".format(pnm=g.proj_name), 'usage': "[opts] ", 'options': """ -d, --outdir= d Specify an alternate directory 'd' for output @@ -45,7 +45,7 @@ command """.format(tool.cmd_help,g.prog_name) } -cmd_args = opt.opts.init(opts_data) +cmd_args = opt.opts.init(opts_data,add_opts=["no_keyconv"]) if len(cmd_args) < 1: opt.opts.usage() @@ -54,6 +54,7 @@ if len(cmd_args) < 1: command = cmd_args.pop(0) if command not in tool.cmd_data: + from mmgen.util import msg msg("'%s': No such command" % command) sys.exit(1) diff --git a/mmgen/main_txcreate.py b/mmgen/main_txcreate.py index f2573193..98725487 100755 --- a/mmgen/main_txcreate.py +++ b/mmgen/main_txcreate.py @@ -17,8 +17,8 @@ # along with this program. If not, see . """ -mmgen-txcreate: Create a Bitcoin transaction from MMGen- or non-MMGen inputs - to MMGen- or non-MMGen outputs +mmgen-txcreate: Create a Bitcoin transaction to and from MMGen- or non-MMGen + inputs and outputs """ import sys @@ -28,6 +28,8 @@ import mmgen.config as g import mmgen.opt as opt from mmgen.tx import * +pnm = g.proj_name + opts_data = { 'desc': "Create a BTC transaction with outputs to specified addresses", 'usage': "[opts] ... [change addr] [addr file] ...", @@ -55,7 +57,7 @@ of the form :. To send all inputs (minus TX fee) to a single output, specify one address with no amount on the command line. -""".format(g=g,pnm=g.proj_name) +""".format(g=g,pnm=pnm) } wmsg = { @@ -64,34 +66,34 @@ ERROR: More than one address found for account: "%s". Your "wallet.dat" file appears to have been altered by a non-{pnm} program. Please restore your tracking wallet from a backup or create a new one and re-import your addresses. -""".strip().format(pnm=g.proj_name), +""".strip().format(pnm=pnm), 'addr_in_addrfile_only': """ Warning: output address {mmgenaddr} is not in the tracking wallet, which means its balance will not be tracked. You're strongly advised to import the address into your tracking wallet before broadcasting this transaction. """.strip(), 'addr_not_found': """ -No data for MMgen address {mmgenaddr} could be found in either the tracking +No data for {pnm} address {mmgenaddr} could be found in either the tracking wallet or the supplied address file. Please import this address into your tracking wallet, or supply an address file for it on the command line. """.strip(), 'addr_not_found_no_addrfile': """ -No data for MMgen address {mmgenaddr} could be found in the tracking wallet. +No data for {pnm} address {mmgenaddr} could be found in the tracking wallet. Please import this address into your tracking wallet or supply an address file for it on the command line. """.strip(), 'no_spendable_outputs': """ No spendable outputs found! Import addresses with balances into your watch-only wallet using '{pnm}-addrimport' and then re-run this program. -""".strip().format(pnm=g.proj_name.lower()), +""".strip(), 'mixed_inputs': """ -NOTE: This transaction uses a mixture of both mmgen and non-mmgen inputs, which +NOTE: This transaction uses a mixture of both {pnm} and non-{pnm} inputs, which makes the signing process more complicated. When signing the transaction, keys for the non-{pnm} inputs must be supplied to '{pnl}-txsign' in a file with the '--keys-from-file' option. Selected mmgen inputs: %s -""".strip().format(pnm=g.proj_name,pnl=g.proj_name.lower()), +""".strip().format(pnm=pnm,pnl=pnm.lower()), 'not_enough_btc': """ Not enough BTC in the inputs for this transaction (%s BTC) """.strip(), @@ -104,7 +106,7 @@ was specified. def format_unspent_outputs_for_printing(out,sort_info,total): pfs = " %-4s %-67s %-34s %-12s %-13s %-8s %-10s %s" - pout = [pfs % ("Num","TX id,Vout","Address","MMgen ID", + pout = [pfs % ("Num","TX id,Vout","Address","{pnm} ID".format(pnm=pnm), "Amount (BTC)","Conf.","Age (days)", "Comment")] for n,i in enumerate(out): @@ -158,8 +160,9 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen while True: cols = get_terminal_size()[0] if cols < g.min_screen_width: - msg("%s-txcreate requires a screen at least %s characters wide" % - (g.proj_name.lower(),g.min_screen_width)) + msg( + "{pnl}-txcreate requires a screen at least {w} characters wide".format( + pnl=pnm.lower(),w=g.min_screen_width)) sys.exit(2) addr_w = min(34+((1+max_acct_len) if show_mmaddr else 0),cols-46) @@ -277,7 +280,7 @@ def select_outputs(unspent,prompt): def mmaddr2btcaddr_unspent(unspent,mmaddr): - vmsg_r("Searching for {g.proj_name} address {m} in wallet...".format(g=g,m=mmaddr)) + vmsg_r("Searching for {pnm} address {m} in wallet...".format(pnm=pnm,m=mmaddr)) m = [u for u in unspent if u.mmid == mmaddr] if len(m) == 0: vmsg("not found") @@ -306,10 +309,10 @@ def mmaddr2btcaddr(c,mmaddr,ail_w,ail_f): if not keypress_confirm("Continue anyway?"): sys.exit(1) else: - msg(wmsg['addr_not_found'].format(mmgenaddr=mmaddr)) + msg(wmsg['addr_not_found'].format(pnm=pnm,mmgenaddr=mmaddr)) sys.exit(2) else: - msg(wmsg['addr_not_found_no_addrfile'].format(mmgenaddr=mmaddr)) + msg(wmsg['addr_not_found_no_addrfile'].format(pnm=pnm,mmgenaddr=mmaddr)) sys.exit(2) return btcaddr diff --git a/mmgen/main_txsend.py b/mmgen/main_txsend.py index 8cc3177a..80f33910 100755 --- a/mmgen/main_txsend.py +++ b/mmgen/main_txsend.py @@ -28,7 +28,8 @@ from mmgen.tx import * from mmgen.util import * opts_data = { - 'desc': "Send a Bitcoin transaction signed by {}-txsign".format(g.proj_name.lower()), + 'desc': "Send a Bitcoin transaction signed by {pnm}-txsign".format( + pnm=g.proj_name.lower()), 'usage': "[opts] ", 'options': """ -h, --help Print this help message diff --git a/mmgen/main_txsign.py b/mmgen/main_txsign.py index 99cd995b..98ea6962 100755 --- a/mmgen/main_txsign.py +++ b/mmgen/main_txsign.py @@ -27,8 +27,11 @@ import mmgen.opt as opt from mmgen.tx import * from mmgen.util import do_license_msg +pnm = g.proj_name +pnl = pnm.lower() + opts_data = { - 'desc': "Sign Bitcoin transactions generated by {}-txcreate".format(g.proj_name.lower()), + 'desc': "Sign Bitcoin transactions generated by {pnl}-txcreate".format(pnl=pnl), 'usage': "[opts] .. [mmgen wallet/seed/words/brainwallet file] ..", 'options': """ -h, --help Print this help message @@ -37,16 +40,16 @@ opts_data = { -i, --info Display information about the transaction and exit -t, --terse-info Like '--info', but produce more concise output -I, --tx-id Display transaction ID and exit --k, --keys-from-file= f Provide additional keys for non-{MMG} addresses +-k, --keys-from-file= f Provide additional keys for non-{pnm} addresses -K, --no-keyconv Force use of internal libraries for address gener- ation, even if 'keyconv' is available --M, --mmgen-keys-from-file=f Provide keys for {MMG} addresses in a key- - address file (output of '{mmg}-keygen'). Permits - online signing without an {MMG} seed source. +-M, --mmgen-keys-from-file=f Provide keys for {pnm} addresses in a key- + address file (output of '{pnl}-keygen'). Permits + online signing without an {pnm} seed source. The key-address file is also used to verify - {MMG}-to-BTC mappings, so its checksum should + {pnm}-to-BTC mappings, so its checksum should be recorded by the user. --P, --passwd-file= f Get MMGen wallet or bitcoind passphrase from file 'f' +-P, --passwd-file= f Get {pnm} wallet or bitcoind passphrase from file 'f' -q, --quiet Suppress warnings; overwrite files without prompting -v, --verbose Produce more verbose output @@ -61,25 +64,25 @@ opts_data = { -o, --old-incog-fmt Use old (pre-0.7.8) incog format -m, --from-mnemonic Generate keys from an electrum-like mnemonic -s, --from-seed Generate keys from a seed in .{g.seed_ext} format -""".format(g=g,MMG=g.proj_name,mmg=g.proj_name.lower()), +""".format(g=g,pnm=pnm,pnl=pnl), 'notes': """ -Transactions with either {MMG} or non-{MMG} input addresses may be signed. -For non-{MMG} inputs, the bitcoind wallet.dat is used as the key source. -For {MMG} inputs, key data is generated from your seed as with the -{mmg}-addrgen and {mmg}-keygen utilities. +Transactions with either {pnm} or non-{pnm} input addresses may be signed. +For non-{pnm} inputs, the bitcoind wallet.dat is used as the key source. +For {pnm} inputs, key data is generated from your seed as with the +{pnl}-addrgen and {pnl}-keygen utilities. Data for the --from- options will be taken from a file if a second file is specified on the command line. Otherwise, the user will be prompted to enter the data. -In cases of transactions with mixed {MMG} and non-{MMG} inputs, non-{MMG} +In cases of transactions with mixed {pnm} and non-{pnm} inputs, non-{pnm} keys must be supplied in a separate file (WIF format, one key per line) using the '--keys-from-file' option. Alternatively, one may get keys from a running bitcoind using the '--force-wallet-dat' option. First import the -required {MMG} keys using 'bitcoind importprivkey'. +required {pnm} keys using 'bitcoind importprivkey'. -For transaction outputs that are {MMG} addresses, {MMG}-to-Bitcoin address +For transaction outputs that are {pnm} addresses, {pnm}-to-Bitcoin address mappings are verified. Therefore, seed material or a key-address file for these addresses must be supplied on the command line. @@ -88,18 +91,18 @@ Seed data supplied in files must have the following extensions: seed: '.{g.seed_ext}' mnemonic: '.{g.mn_ext}' brainwallet: '.{g.brain_ext}' -""".format(g=g,MMG=g.proj_name,mmg=g.proj_name.lower()) +""".format(g=g,pnm=pnm,pnl=pnl) } wmsg = { 'mm2btc_mapping_error': """ -MMGen -> BTC address mappings differ! +{pnm} -> BTC address mappings differ! From %-18s %s -> %s From %-18s %s -> %s -""".strip(), +""".strip().format(pnm=pnm), 'removed_dups': """ -Removed %s duplicate wif key%s from keylist (also in {MMG} key-address file -""".strip().format(MMG=g.proj_name), +Removed %s duplicate wif key%s from keylist (also in {pnm} key-address file +""".strip().format(pnm=pnm), } def get_seed_for_seed_id(seed_id,infiles,saved_seeds): @@ -138,7 +141,7 @@ def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds): seed = get_seed_for_seed_id(seed_id,infiles,saved_seeds) addr_nums = [int(i[9:]) for i in mmgen_addrs if i[:8] == seed_id] opt.gen_what = "ka" - ai = generate_addrs(seed,addr_nums) + ai = generate_addrs(seed,addr_nums,source="txsign") d += [("{}:{}".format(seed_id,e.idx),e.addr,e.wif) for e in ai.addrdata] return d @@ -189,10 +192,11 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys): return sig_tx -def check_maps_from_seeds(maplist,label,infiles,saved_seeds,return_keys=False): +def check_maps_from_seeds(maplist,what,infiles,saved_seeds,return_keys=False): if not maplist: return [] - qmsg("Checking MMGen -> BTC address mappings for %ss (from seeds)" % label) + qmsg("Checking {pnm} -> BTC address mappings for {w}s (from seed(s))".format( + pnm=pnm,w=what)) d = get_keys_for_mmgen_addrs(maplist.keys(),infiles,saved_seeds) # 0=mmaddr 1=addr 2=wif m = dict([(e[0],e[1]) for e in d]) @@ -209,8 +213,8 @@ def check_maps_from_seeds(maplist,label,infiles,saved_seeds,return_keys=False): def missing_keys_errormsg(addrs): Msg(""" A key file must be supplied (or use the '--use-wallet-dat' option) -for the following non-{} address{}:\n {}""".format( - g.proj_name,suf(addrs,"a"),"\n ".join(addrs)).strip()) +for the following non-{pnm} address{suf}:\n {l}""".format( + pnm=pnm, suf=suf(addrs,"a"), l="\n ".join(addrs)).strip()) def parse_mmgen_keyaddr_file(): @@ -225,7 +229,7 @@ def parse_mmgen_keyaddr_file(): def parse_keylist(from_file): fn = opt.keys_from_file - d = get_data_from_file(fn,"non-%s keylist" % g.proj_name) + d = get_data_from_file(fn,"non-{pnm} keylist".format(pnm=pnm)) enc_ext = get_extension(fn) == g.mmenc_ext if enc_ext or not is_utf8(d): if not enc_ext: qmsg("Keylist file appears to be encrypted") @@ -250,7 +254,8 @@ def parse_keylist(from_file): # Check inputs and outputs maps against key-address file, deleting entries: def check_maps_from_kafile(imap,what,kadata,return_keys=False): - qmsg("Checking MMGen -> BTC address mappings for %ss (from key-address file)" % what) + if not kadata: return [] + qmsg("Checking {pnm} -> BTC address mappings for {w}s (from key-address file)".format(pnm=pnm,w=what)) ret = [] for k in imap.keys(): if k in kadata.keys(): @@ -372,7 +377,10 @@ for tx_num,tx_file in enumerate(tx_files,1): data = make_tx_data("{} {} {t}".format(*metadata[:2], t=make_timestamp()), sig_tx['hex'], inputs_data, b2m_map, comment) w = "signed transaction{}".format(tx_num_str) - write_to_file(outfile,data,w,(not opt.quiet),True,False) + if keypress_confirm("Save signed transaction?",default_yes=False): + write_to_file(outfile,data,w,(not opt.quiet),True,False) + else: + msg("Signed transaction not saved") else: msg_r("failed\nSome keys were missing. ") msg("Transaction %scould not be signed." % tx_num_str) diff --git a/mmgen/main_walletchk.py b/mmgen/main_walletchk.py index f5490bc2..935aa8b2 100755 --- a/mmgen/main_walletchk.py +++ b/mmgen/main_walletchk.py @@ -28,15 +28,15 @@ from mmgen.util import * from mmgen.crypto import * opts_data = { - 'desc': """Check integrity of an {} deterministic wallet, display + 'desc': """Check integrity of an {pnm} deterministic wallet, display its information, and export seed and mnemonic data. - """.format(g.proj_name), + """.format(pnm=g.proj_name), 'usage': "[opts] [filename]", 'options': """ -h, --help Print this help message -d, --outdir= d Specify an alternate directory 'd' for output -e, --echo-passphrase Print passphrase to screen when typing it --P, --passwd-file= f Get MMGen wallet passphrase from file 'f' +-P, --passwd-file= f Get {pnm} wallet passphrase from file 'f' -q, --quiet Suppress warnings; overwrite files without prompting -r, --usr-randchars= n Get 'n' characters of additional randomness from user (min={g.min_urandchars}, max={g.max_urandchars}) @@ -49,7 +49,7 @@ opts_data = { -o, --old-incog-fmt Use old (pre-0.7.8) incog format -m, --export-mnemonic Export the wallet's mnemonic to file -s, --export-seed Export the wallet's seed to file -""".format(g=g), +""".format(g=g,pnm=g.proj_name), 'notes': """ Since good randomness is particularly important for incognito wallets, @@ -67,7 +67,7 @@ def wallet_to_incog_data(infile): d[1][0], d[1][1], d[2].split(":")[0], d[3], d[4] while True: - passwd = get_mmgen_passphrase("{} wallet".format(g.proj_name)) + passwd = get_mmgen_passphrase("{pnm} wallet".format(pnm=g.proj_name)) key = make_key(passwd, salt, preset, "main key") seed = decrypt_seed(enc_seed, key, seed_id, key_id) if seed: break diff --git a/mmgen/main_walletgen.py b/mmgen/main_walletgen.py index cdb9dd7d..05a94a3c 100755 --- a/mmgen/main_walletgen.py +++ b/mmgen/main_walletgen.py @@ -28,8 +28,10 @@ import mmgen.opt as opt from mmgen.util import * from mmgen.crypto import * +pnm = g.proj_name + opts_data = { - 'desc': "Generate an {} deterministic wallet".format(g.proj_name), + 'desc': "Generate an {pnm} deterministic wallet".format(pnm=pnm), 'usage': "[opts] [infile]", 'options': """ -h, --help Print this help message @@ -42,7 +44,7 @@ opts_data = { Allowed symbols: A-Z, a-z, 0-9, " ", "_", ".") -p, --hash-preset= p Use scrypt.hash() parameters from preset 'p' (default: '{g.hash_preset}') --P, --passwd-file= f Get MMGen wallet passphrase from file 'f' +-P, --passwd-file= f Get {pnm} wallet passphrase from file 'f' -q, --quiet Produce quieter output; overwrite files without prompting -r, --usr-randchars= n Get 'n' characters of additional randomness from @@ -58,7 +60,7 @@ opts_data = { -o, --old-incog-fmt Use old (pre-0.7.8) incog format -m, --from-mnemonic Generate wallet from an Electrum-like mnemonic -s, --from-seed Generate wallet from a seed in .{g.seed_ext} format -""".format(seed_lens=",".join([str(i) for i in g.seed_lens]), g=g), +""".format(seed_lens=",".join([str(i) for i in g.seed_lens]),g=g,pnm=pnm), 'notes': """ By default (i.e. when invoked without any of the '--from-' options), @@ -106,16 +108,17 @@ just hit ENTER twice. ############################## EXPERTS ONLY! ############################## A brainwallet will be secure only if you really know what you're doing and -have put much care into its creation. {} assumes no responsibility for -coins stolen as a result of a poorly crafted brainwallet passphrase. +have put much care into its creation. The creators of {pnm} assume no +responsibility for coins stolen as a result of a poorly crafted brainwallet +passphrase. A key will be generated from your passphrase using the parameters requested by you: seed length {}, hash preset '{}'. For brainwallets it's highly -recommended to use one of the higher-numbered presets +recommended to use one of the higher-numbered presets. Remember the seed length and hash preset parameters you've specified. To generate the correct keys/addresses associated with this passphrase in the -future, you must continue using these same parameters +future, you must continue using these same parameters. """, } @@ -145,7 +148,7 @@ do_license_msg() if opt.from_brain and not opt.quiet: confirm_or_exit(wmsg['brain_warning'].format( - g.proj_name, *get_from_brain_opt_params()), + pnm=pnm, *get_from_brain_opt_params()), "continue") if infile or any([ @@ -160,7 +163,7 @@ salt = sha256(get_random(128)).digest()[:g.salt_len] qmsg(wmsg['choose_wallet_passphrase'] % opt.hash_preset) -passwd = get_new_passphrase("new {} wallet".format(g.proj_name)) +passwd = get_new_passphrase("new {pnm} wallet".format(pnm=pnm)) key = make_key(passwd, salt, opt.hash_preset) diff --git a/mmgen/mn_electrum.py b/mmgen/mn_electrum.py index 8c17c671..1926038c 100755 --- a/mmgen/mn_electrum.py +++ b/mmgen/mn_electrum.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ------------------------------------------------------------------------------ -# MMgen note: this is a sorted version of the wordlist. The original +# MMGen note: this is a sorted version of the wordlist. The original # can be found at: # https://github.com/spesmilo/electrum/blob/master/lib/mnemonic.py # and in the file 'wordlists/mnemonic.py' of the mmgen distribution. diff --git a/mmgen/opts.py b/mmgen/opts.py index 8722dab8..9feeb060 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -32,10 +32,10 @@ def usage(): def print_version_info(): Msg(""" -{progname_uc} version {g.version}. Part of the {g.proj_name} suite, a Bitcoin -cold-storage solution for the command line. Copyright (C) {g.Cdates} -by {g.author} {g.email} -""".format(g=g,progname_uc=g.prog_name.upper()).strip()) +{progname_uc} version {g.version} +Part of the {pnm} suite, a Bitcoin cold-storage solution for the com- +mand line. Copyright (C) {g.Cdates} {g.author} {g.email} +""".format(pnm=g.proj_name,g=g,progname_uc=g.prog_name.upper()).strip()) def warn_incompatible_opts(incompat_list): bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in incompat_list] @@ -61,7 +61,6 @@ def typeconvert_from_dfl(key): 'bool': 'a boolean value', } m = [d[k] for k in d if __builtins__[k] == vtype] - msgrepr_exit(key,vtype) fs = "'%s': invalid parameter for '--%s' option (not %s)" msg(fs % (opt.__dict__[key],opt.replace("_","-"),m)) sys.exit(1) diff --git a/mmgen/seed.py b/mmgen/seed.py index bc146fea..e947d5ee 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -29,6 +29,8 @@ from mmgen.util import * from mmgen.bitcoin import b58encode_pad,b58decode_pad from mmgen.crypto import * +pnm = g.proj_name + class Seed(MMGenObject): def __init__(self,seed_bin=None): if not seed_bin: @@ -293,7 +295,7 @@ class SeedFile (SeedSourceUnenc): class Wallet (SeedSourceEnc): - desc = "%s wallet" % g.proj_name + desc = "{pnm} wallet".format(pnm=pnm) def _encode(self): d = self.ssdata @@ -341,8 +343,8 @@ class Wallet (SeedSourceEnc): def _deformat(self): - qmsg("Getting {} wallet data from file '{}'".format( - g.proj_name,self.infile.name)) + qmsg("Getting {pnm} wallet data from file '{f}'".format( + pnm=pnm,f=self.infile.name)) lines = self.fmt_data.rstrip().split("\n") @@ -518,13 +520,13 @@ to exit and re-run the program with the '--old-incog-fmt' option. d.incog_id = self._make_iv_chksum(d.iv) d.enc_incog_data = raw_d[g.aesctr_iv_len:] msg("Incog ID: %s" % d.incog_id) - qmsg("Check the applicable value against your records.") + qmsg("Check the applicable value against your records") k = 'incog_iv_id_hidden' if opt.from_incog_hidden else 'incog_iv_id' vmsg("\n%s\n" % self._icg_msg[k]) def _decode(self): d = self.ssdata - prompt_info="{} incognito wallet".format(g.proj_name) + prompt_info="{pnm} incognito wallet".format(pnm=pnm) while True: passwd = get_mmgen_passphrase(prompt_info+" "+d.incog_id) diff --git a/mmgen/test.py b/mmgen/test.py index 25a1e8a3..47ece172 100755 --- a/mmgen/test.py +++ b/mmgen/test.py @@ -17,7 +17,7 @@ # along with this program. If not, see . """ -addr.py: Shared routines for the test suites +test.py: Shared routines for the test suites """ import sys,os @@ -86,6 +86,7 @@ def cmp_or_die(s,t,skip_ok=False): if s == t: if not skip_ok: ok() else: - msg(red("Recoded data:\n%s\ndiffers from original data:\n%s\n" % - (repr(t),repr(s)))) + sys.stderr.write(red( + "ERROR: recoded data:\n%s\ndiffers from original data:\n%s\n" % + (repr(t),repr(s)))) sys.exit(3) diff --git a/mmgen/tool.py b/mmgen/tool.py index dde7036d..4958bfd5 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -30,6 +30,8 @@ from mmgen.crypto import * from mmgen.util import * from mmgen.tx import * +pnm = g.proj_name + from collections import OrderedDict cmd_data = OrderedDict([ ("help", []), @@ -75,10 +77,10 @@ cmd_data = OrderedDict([ ("listaddresses",['minconf [int=1]','showempty [bool=False]','pager [bool=False]']), ("getbalance", ['minconf [int=1]']), - ("txview", [' [str]','pager [bool=False]','terse [bool=False]']), + ("txview", ['<{pnm} tx file> [str]','pager [bool=False]','terse [bool=False]'.format(pnm=pnm)]), - ("addrfile_chksum", [' [str]']), - ("keyaddrfile_chksum", [' [str]']), + ("addrfile_chksum", ['<{pnm} addr file> [str]'.format(pnm=pnm)]), + ("keyaddrfile_chksum", ['<{pnm} addr file> [str]'.format(pnm=pnm)]), ("find_incog_data", [' [str]',' [str]','keep_searching [bool=False]']), ("encrypt", [' [str]','outfile [str=""]','hash_preset [str=""]']), @@ -150,7 +152,7 @@ cmd_help = """ IMPORTANT NOTE: Though {pnm} mnemonics use the Electrum wordlist, they're computed using a different algorithm and are NOT Electrum-compatible! -""".format(pnm=g.proj_name) +""".format(pnm=pnm) def tool_usage(prog_name, command): Msg("USAGE: '%s %s%s'" % (prog_name, command, @@ -486,7 +488,7 @@ def decrypt(infile,outfile="",hash_preset=""): if dec_d: break msg("Trying again...") if outfile == '-': - write_to_stdout(dec_d,"decrypted data",confirm=True) + write_to_stdout(dec_d,"decrypted data",confirm=not opt.quiet) else: if not outfile: outfile = os.path.basename(infile) diff --git a/mmgen/tx.py b/mmgen/tx.py index 687de16c..caed7432 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -100,16 +100,21 @@ def wiftoaddr(s): if not hex_key: return False return privnum2addr(int(hex_key,16),compressed) -def is_valid_tx_comment(s, verbose=True): + +def is_valid_tx_comment(s): + + try: s = s.decode("utf8") + except: + msg("Invalid transaction comment (not UTF-8)") + return False + if len(s) > g.max_tx_comment_len: - if verbose: msg("Invalid transaction comment (longer than %s characters)" % + msg("Invalid transaction comment (longer than %s characters)" % g.max_tx_comment_len) return False - try: s.decode("utf8") - except: - if verbose: msg("Invalid transaction comment (not UTF-8)") - return False - else: return True + + return True + def check_addr_label(label): @@ -149,7 +154,7 @@ def view_tx_data(c,inputs_data,tx_hex,b2m_map,comment,metadata,pager=False,pause if comment: out += "Comment: %s\n%s" % (comment,enl) out += "Inputs:\n" + enl - nonmm_str = "non-%s address" % g.proj_name + nonmm_str = "non-{pnm} address".format(pnm=g.proj_name) total_in = 0 for n,i in enumerate(td['vin']): @@ -241,7 +246,7 @@ def parse_tx_file(tx_data,infile): if comment == False: err_str = "encoded comment (not base58)" else: - if is_valid_tx_comment(comment,True): + if is_valid_tx_comment(comment): comment = comment.decode("utf8") else: err_str = "comment" @@ -268,7 +273,7 @@ def get_wif2addr_f(): def get_tx_comment_from_file(infile): s = get_data_from_file(infile,"transaction comment") - if is_valid_tx_comment(s, verbose=True): + if is_valid_tx_comment(s): return s.decode("utf8").strip() else: sys.exit(2) @@ -278,7 +283,7 @@ def get_tx_comment_from_user(comment=""): while True: s = my_raw_input("Comment: ",insert_txt=comment.encode("utf8")) if s == "": return False - if is_valid_tx_comment(s, verbose=True): + if is_valid_tx_comment(s): return s.decode("utf8") except KeyboardInterrupt: msg("User interrupt") diff --git a/mmgen/util.py b/mmgen/util.py index 0081e39b..694483a0 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -27,6 +27,8 @@ from string import hexdigits import mmgen.config as g +pnm = g.proj_name + _red,_grn,_yel,_cya,_reset = ( ["\033[%sm" % c for c in "31;1","32;1","33;1","36;1","0"] ) @@ -493,7 +495,7 @@ def get_data_from_wallet(infile,silent=False): # Don't make this a qmsg: User will be prompted for passphrase and must see # the filename. if not silent and not opt.quiet: - msg("Getting {} wallet data from file '{}'".format(g.proj_name,infile)) + msg("Getting {pnm} wallet data from file '{f}'".format(pnm=pnm,f=infile)) f = open_file_or_exit(infile, 'r') @@ -609,7 +611,7 @@ def get_seed_from_seed_data(words): msg("Valid seed data for seed ID %s" % make_chksum_8(seed)) return seed else: - msg("Invalid checksum for {} seed".format(g.proj_name)) + msg("Invalid checksum for {pnm} seed".format(pnm=pnm)) return False diff --git a/test/ref/1378FC64-6F0F9BB4[192,1].mmdat b/test/ref/1378FC64-6F0F9BB4[192,1].mmdat new file mode 100644 index 00000000..90dc7cd4 --- /dev/null +++ b/test/ref/1378FC64-6F0F9BB4[192,1].mmdat @@ -0,0 +1,6 @@ +5439c5 +No Label +1378fc64 6f0f9bb4 192 NE 20150406_105042 +1: 12 8 1 +0e8caa N7Co eyLd LbJ1 ACfm s4g4 rV +f5fdd7 CF2X P6rr ng9z uQev Ldpv 1NeA BarC 6vUC f diff --git a/test/ref/1378FC64-B55E9958-77256FC1[192:1].incog.offset123 b/test/ref/1378FC64-B55E9958-77256FC1[192:1].incog.offset123 new file mode 100644 index 0000000000000000000000000000000000000000..9dda168f21087f53480537699f4f1cc7cdd273c7 GIT binary patch literal 1024 zcmV+b1poUidfFcPseM;z%G7U%FrCw3^7GEE@;y=rilWJmd!si`cXfcVrvegpTfUMI z`o({eAOFx4`SaL*w{3?bmJuUscFbXT9rgoJ`cU4q-Z|Ci;{C#MJTO%%3Z^{fY#%^-uGY_EOda;wcwZAv~O;EKEb3$QxJH)Gln!vFoSGinCyU&7a*7eXauoJi3 zpu>o*(247*(I!*1W@_;WcFiYB)nbynpeX##F{hTg_a&ip)rNR6jDWK<5$c?o!s42GcyUOe}FU z)>F-YNUxdW8lRPMHmP#0m%{G!Q_a{$TQBJjoS$`3)NxCo?c7cD1KBi{dd~YGZNoQd z%4OaX%~r!?@Rf);#(%PLyC!fsw)GA5K%69z8g%s0UIrH`cR)Zk90at$N{6dRF{W{I z3=RZzZX#xJFT;<={2`f%kYpRN6Z9Z(2w0zt7EvhPN#g>(%PsTnA`S3%S6m{2cDk&) z;L762z^efiH5+_Y~`oj_0 zObacnr?_Mf+WWzPp+CWj$onNn1%!EiCBHIzcr@+~-5H*|WF8uEo5 zDina2iVdh5iH@`HGqP&)*8HaP`uDE!pWPdH)zC_i(?Y?wya2Iz(lG1f0HR0PV{h9P u!S8vZ-xP%Zb#UC?^mC+DpQ4DcV}4}qU?^|HT^A;lNtjQ8h$`1b%8NJcu=p)idX4!>Hntj5|jOLolAa6XvD=ZtSc?j(DenBNIPJ5f71E(T#0U79yi` z0Ps%3IUA-%wg8jO_+KwW&aU9Af<(kb#V}KNuRV^AgKH zA!vFzR-X848-D;fh?An_+C=l*=2CnffsHOki$ioF*^;}h z8h)f9F@G7d@~9_pifsAeqNlCPuI7k{J!R5yE*n`&h8C&qMa zsYR*YlYY;#L0l2y*NymS3MblJ*)x&d2F3cr(5jjI1g$fX#nIn@^U=X^0lsE*bzHTX zfZ)Y?&SnfH_`Ofgg)~jdt1*ygWTi&n;cxc@kY$-TCh6LFIzgjMU}qFh0r-L1BQ4KS z0lGj~?UIx}1z0}g0ef6rOnmy`epvB$0N&s|2xYmAqk^oYmEv)q>Qo1G>Ws_&}OweaQ*!D$ydNm~J8MHmul< zgK+3JvsKz!D?mSE65V6|Ie;pIgHk3v9VT-7C-%OoNRPu1x}04+LjRpJ#m|n*EtZPM0&Ej zA77qgJnQrvq&aCk5$?~XVoUkSOOrF7d&ip!Eqqnz70A@^ma3BX15<&!M=a(PAtA7b zWT5k9aWLO0=)r@f`l;&ksU`1F*dJ-M*olUR!uwTQUpeB#@<7-x-md{(PlA ztgX#6-a;w94Rt`Dt(^NzOnZSd_1*?pCuML|*-NEeosz!otG&()4JhG3rVb0am zf%u3-4uggVX86^G@AgL^*gRw{6E+;bS7@SWP{LWOQlS!8Kgale9`PZlyMTz`P4aw=)Nl=zoAojiy8F4VTK@Y2que&=Vh4#TwCx^jai>vS#1bDkhKA uY*@TrlA+n!e=^sXZW7GmGY9zn>NCNJQN20^@ytn!$RS@hP|{!pLH&gQ literal 0 HcmV?d00001 diff --git a/test/ref/1378FC64.mmseed b/test/ref/1378FC64.mmseed new file mode 100644 index 00000000..affd19f9 --- /dev/null +++ b/test/ref/1378FC64.mmseed @@ -0,0 +1 @@ +6bbc91 7L6o G2dR nAFk hncM Q7TU 8Gcc CEGP oKxx C diff --git a/test/ref/1378FC64.mmwords b/test/ref/1378FC64.mmwords new file mode 100644 index 00000000..1a704acd --- /dev/null +++ b/test/ref/1378FC64.mmwords @@ -0,0 +1 @@ +duck memory screen world knee thank pray ignore physical season sanity anymore view prince fix compare mother make diff --git a/test/ref/98831F3A-27F2BF93[256,1].mmdat b/test/ref/98831F3A-27F2BF93[256,1].mmdat new file mode 100644 index 00000000..9874260c --- /dev/null +++ b/test/ref/98831F3A-27F2BF93[256,1].mmdat @@ -0,0 +1,6 @@ +cd828f +"#$%&()*+,- ./0123456789:;<=>?@AIZ[\]^_`aiz{|}~' +98831f3a 27f2bf93 256 NE 20150405_075000 +1: 12 8 1 +9440eb NBDH bKqG a23q FtYi nRo1 kk +7a2f32 5nZf LqjP R9bj vgzc sMGr WPtu PR7S 6NpZ pgGd fc4e QCKt diff --git a/test/ref/98831F3A-F59B07A0-559CEF19[256:1].incog.offset123 b/test/ref/98831F3A-F59B07A0-559CEF19[256:1].incog.offset123 new file mode 100644 index 0000000000000000000000000000000000000000..1c89227086fa9d9bc330689732ce2a7908425741 GIT binary patch literal 1024 zcmV+b1poWGjvOo%n8NW^@lKt`ZK2y$h&d9&sKFd!k~xDy&6mC^eWYS}zQn z6%=3jwCAc`9-Kvtu}5pwsz{eB<=ILJ*__R=KpQu^904*^6+%&`=j7jxT!J3p1-xT= zkuzW1t@6+x7zlN2mk-S8x4YHm?H9=v(3HUieQ(M-GyQ$l*ExtD+2}XoYK>`I-XGM_ zMUkiR`L>LC>5-BtW<23&zXKerz0>6(tR(ohCD5RCJk z?V;K;RoQ#tDDfvbCVEMRxN z!LTJ$D_Wf|hVaRVj>V$aauk1>{4n@;%2_?q82YI_|x z%_PIrzYJXJdNng3PFgAY4badci0ojKj}wh<2TgXw%Uo1@|6s*K8$wk?p$D|Z&1Sd` zQ(_1#-j)ff<(>l7n1EO>0gOv-Zag5d>{{Xn-AM2&k`OU)0gAsZA0&|TvR8!@zE~4- zxQ|D+uFL8q`?3$44kU<#$^S11BmjKZQ>wXIxn1#%jIulX!VRxVujhjFi%T)OHImvw z$8UrH%H`;KkMP4}Jm5-?ile#X8VvD|bMWp)#-1EG_pq)32aM3bVf<62B<~{o$dAQ@ zU6&@G6z%9g+t~1*^!shxwnXbzn=oWF zfho8VScmrl{7Bz=YhQK$1~vMv5&6?90jQ(7M;72tv;c`3S$M1`^@soh10D`Aec<;~ z#K6EPo7giRIWbn4bnwFHgfJ&T6){WX7+$5>Z!N;J8~x0P)u#iVCH)%&=4OGlpv1E1 uPR&q9Xc5gt7%h8EniT0twOz(IKo*-1P7`Wn;OZUXQ2xNLWZ^x9&qiVs2nL`4 literal 0 HcmV?d00001 diff --git a/test/ref/98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123 b/test/ref/98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123 new file mode 100644 index 0000000000000000000000000000000000000000..8506b42cd9bb5eac4c3ec0133e8b322cadef9896 GIT binary patch literal 1024 zcmV+b1poU{R6+ZcnWB73W4USm&ytbMH~GD}Vg0AM0YM>uP3$Rhx99#gO$Lhto7h5DXf`I@?(}xaE%N%iaqxkRXir;2Q`wi|M1s0 zw~rHID(;2Qi`unE8*N_*?i8W3+Al{GtLV(_?2O%T&vvNXI=^8Hk1|+C(ab{j!mt-% zKDey2hUhYDHVNMOJ9hyNW4PY<9Q)hgrfNX6N#X6c9BnVdNNo5SIkmL3?Z;-TgQ9L%2a;Q1&(B~ zJD>1?Izh2gF2*s0UqcU;?M1EM;E4twfOgLV;k72me(sbc$r@T{FJEqQ2rqhQN>~y< z+L6y7eaglQ9D!nl);{65s~}gIo%5d)YF{I(QaA}1&SBvkMob5OxZo8;N}V>u#J!&u z{Y|L@Gr`h?SR{)gVpU`9F8h|xC-0;d<2`HdBsma;a(X^`=AkF*bdimD9RS&Nu2U^p zxdX#DA6w}_5)9>HM&c#xaIg!DBPlYySPn;<$@|Y4=9~-vYuMd#Ecd5^CY?<>hZ%F) zhSA=7^Xs)%rq?`p?@YW5xg#I8_d7CcxBVUMCJHShRa&Dj??L71TMSKv?6GSB+NgGm>*-{=BVllz1Yp?Y=-9TmQvb{Yo`F^=o8c0zw6>{F*ghBs@c`U5 zYS`NKSg~s=@QV*4Ge5d%2JLO(a58seHgVq!N4oiF~OVlejl6 z*1)cgGbQGZ``8P^o8aF_=c}6DN%7PX!hK!EQ4fcnFiRo7y0_A2uR<^cOi-1;0Q-G7 zK~7XYC4Qmg7wYq>FeFVkIR%GNK{Psc0SSpg;UH&BXNrXkWt=*Ku@hYe6v4JJ;bE$C z90}q{qYNl#n8YuN{K(bnHB3Al=#|?1&28F@{Z*oJCnxBuws+O}kdAOdAbre){U7E}%L=b@`b!BQ uTFzaF37G(Z3xxoT4}g=5l&CeGTO9VNc9ILCv+~Ng_Z716#=mJ1m4i~auI|?@AZ[]_az|' + 32 19X3wLG3m7Dg6o5bppk1eqwkLiLVSJ8t1H + 33 177t1mCffzMWihi9w2Jbb9MQ331zFTxmDJ + 500 1EZNuddPnaZFah9QVbGvzvTcP4KeRrRFt8 + 501 1ET1CZJtXZanLqbGhFkd4h1hsHengakjqV + 1010 1DysuxsnRA46wd9bpFhLog2jwtpARmP6BY + 1011 1DD7mfGAPWme3p8f52AJA9rNQ2SxV1ZUe6 +} diff --git a/test/ref/98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc b/test/ref/98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc new file mode 100644 index 0000000000000000000000000000000000000000..13020434a2df1a3a2a160c11496ea06afcf1f3b4 GIT binary patch literal 1454 zcmV;f1yTCGsD}ZpLm(byZ*jon_=OlHtc^PIbH5GW5}20gca_mEw4DpE11V z@%e1GbVf3eG6>T8UtBr=m>(np_a2H^C=bZsoWxU+_t+hqpD7w-5iw1HoambbB`dBx zO!qelBC=Q%9*m*u=LJMidrdz1I^N}U6oL2Se0 z?2kgW;iHl)bASCIuneTY<%#rM9P07MRI_=$N#C&q@9A#%2Mu{3jzvn1_<8Qomj}k% zAvU@Z9^})0Hi|peA_qmEi@e%%NNBESrHC{s<9nmAr6w+?93s8aUT1~1PcH;0)pArj4CoGC36@FnSNN&+@A0AP|1uQjq)26)cC|;zr0xxUn7iz&A2LkxO1emH_i# zc5W4T3Pl@|SD9Vhk!+G`HPC}o?*H|J3I~?<%2=yW7l(6{^X}L;ISoMgJ}&9Bff)dD_ z^#}PIO@M?Vee*dkKxT#QA1bU=zFLFYCtGd+izWg<+Z-qiM*t>$+`~tlOy?zW*>Ed} z*I>O6gheT?27DspQ=7VfKqlfq)eZ}=l7F2(`OOb`yPaJrOc!{0Ayh@j?k?cFZD%GK0 z0080Y)@o)oG)TIp8)WSeMO(5^*bC?ZKuV&yZCLOJP<}4htium96YPbCezeu+57vj zaYbkLH%44b)FWn@&3;VqG~wX8-Alp>4`kWs)Vg z@iti=nUlQP9T2Xq5-8CL;S8;O0jel5^hEMjElp-E7v z*~XF;OMV$HNrNd>kPmn7_=s5eX7aZb7Ho%xKiCp>y5HHA)*G~eLi77G^;~acrMS~U z1XALO5TC#4wr}yL8yfu>zxLURnA;s!_@U@syv+Sts-^Cwx0vBV^2MPR>nB{wCI5yu zNq1vQ#q>?Esl4cxBO+`qH9YbUZm1!>*t6Msul1)ah?99{T;$uv?hx#}7>nmQ{#;~* z%+#i!01OjWlMHp!i(A9FKXCKgC^CYyfY*piH;WnjOlnKge-77_Q(syM@S>`Hb+pFz zv3A6JyS-*NHh0W(?0(4g&0i;Z#?3iSlR%`QKwFfYOj<1>_{l^CS-iRt^BW{@)ysnK I@0)5p<#<}lB>(^b literal 0 HcmV?d00001 diff --git a/test/ref/FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123 b/test/ref/FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123 new file mode 100644 index 00000000..9f220bd1 --- /dev/null +++ b/test/ref/FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123 @@ -0,0 +1,6 @@ +.OQe%S)l[s!֌JUz]\q}jm Yr١M_/_Q#6޷=gzȜE˲ 9zT',ħaZ8_NQ U?M/jP_ݍXn0ԃo ֧'+?L6Hnw>H|\ž+3I,ΫfHL%Pۡ_`~,2vhYAMdW8%HǝLE҆nȥvljQ_`'^`ubzQNrBvL_BKN=jeX z5{#6AgQb}1S-3kxyj7)u+K#YdJI=7B+*6A{bR>6&%X&itOZS{uH(do|=(}@)vW;`B zAU8$SIV+cyI*l+jZ%XSh43lnTT7sZ%6b+A4710^zTB5X`w0OgJ8K$srV zm(MX=+f`h@EuMTl*d)#T~AsUw=aREJxWr zjI5;l>{B2~Y9^9;rD}BP$lID!?oTh)(zH~E)Ng@MrmLdAd?C3GrI>wB)?Z>26QETs zv;PbQf{fXaa(z_+x|z$k{toS+9-OXl{jqqe&C`$RWWoEDo$Nt` zm~}!$+IO}am7*3ZXckAm5r})hxUztM7#S{u2v57EAHxl{&9lmlxP>X8SlWJ~b4ROpa(& zbvN(3AVabR!U*cTs-oh0i$C`Fy;B~pe}-U$O&yvX;aG5UiQt$Vj2xZY_#5UC$+dyD zSq9elJ}W%FH{`ie2npu>%a#4;tOO)Z1lz{UwiSN}~Y z9R&L1$_~AZk2+x|AOWje8ehNrQ@vnHaFjqkQxx4p_ZHVivpOyVJ%yYd1V==}g*Poz zrMB?;#|Bl9LYS+_MzP5I#;ZbtreY3%nmT{;OM%ojR#Lg4(kC!Jr)i*?*(TG5paZyo z+cL?>Bb(K%2=Ax@_)brF?Syn5<5kmheRIh{X&76e3x&bDuOc6 u{4lS(6d$C0*NizWGKwMf%A=wy>c)&+yO{#=QI5D?EL?Ub326HQkGmh`s`3c{ literal 0 HcmV?d00001 diff --git a/test/ref/FE3C6545-D782B529[128,1].mmdat b/test/ref/FE3C6545-D782B529[128,1].mmdat new file mode 100644 index 00000000..204c480a --- /dev/null +++ b/test/ref/FE3C6545-D782B529[128,1].mmdat @@ -0,0 +1,6 @@ +09f434 +No Label +fe3c6545 d782b529 128 NE 20150406_104849 +1: 12 8 1 +efa838 6aNb kfGu YGBy SxTe amwC q4 +3548be 8MM2 fxNv Sr7N h4NA WXv2 wL diff --git a/test/ref/FE3C6545.mmseed b/test/ref/FE3C6545.mmseed new file mode 100644 index 00000000..f52e9ec3 --- /dev/null +++ b/test/ref/FE3C6545.mmseed @@ -0,0 +1 @@ +0e6d52 9aFM LL5z pLA7 DNLu vAha hT diff --git a/test/ref/FE3C6545.mmwords b/test/ref/FE3C6545.mmwords new file mode 100644 index 00000000..d923420f --- /dev/null +++ b/test/ref/FE3C6545.mmwords @@ -0,0 +1 @@ +dude foot desperate tie stood themselves trip descend cease suicide apple busy diff --git a/test/ref/brainwallet b/test/ref/brainwallet new file mode 100644 index 00000000..e206674b --- /dev/null +++ b/test/ref/brainwallet @@ -0,0 +1 @@ +A brainwallet with some non-standard spacing diff --git a/test/ref/brainwallet-spaced b/test/ref/brainwallet-spaced new file mode 100644 index 00000000..3d8752e8 --- /dev/null +++ b/test/ref/brainwallet-spaced @@ -0,0 +1,11 @@ + + A + + brainwallet + +with some + non-standard + + spacing + + diff --git a/test/ref/tx_FFB367[1.234].raw b/test/ref/tx_FFB367[1.234].raw new file mode 100644 index 00000000..b0f29d19 --- /dev/null +++ b/test/ref/tx_FFB367[1.234].raw @@ -0,0 +1,5 @@ +FFB367 1.234 20150405_102927 +01000000013364630b6d290a82c822facc2f7c1db4452cea459b2ce22371135530485a5d010600000000ffffffff0205d7d600010000001976a914bba3993079ccdf40c9bbbe495473f0b3d2dc5eec88ac40ef5a07000000001976a914abe58e1e45f6176910a4c1ac1ee62328d5cc4fd588ac00000000 +[{'comment': u'Test Wallet', 'mmid': u'98831F3A:500', 'vout': 6, 'txid': u'015d5a483055137123e22c9b45ea2c45b41d7c2fccfa22c8820a296d0b636433', 'amount': Decimal('44.32452045'), 'confirmations': 495L, 'address': u'1EZNuddPnaZFah9QVbGvzvTcP4KeRrRFt8', 'spendable': False, 'scriptPubKey': '76a91494b93bbe8a32f1db80b307482e83c25fa4e99b8c88ac'}] +{u'1J79LtWctedRLnMfFNRgzzSFsozQqDeoKD': ('98831F3A:3', u''), u'1EZNuddPnaZFah9QVbGvzvTcP4KeRrRFt8': (u'98831F3A:500', u'Test Wallet'), u'1GfuYaKHrhdiVybXMGCcjadSgfjvpdt2x9': ('98831F3A:2', u'')} +3SBcsGkhcKRVB2gr98BmscU8HtWJ12HTXpJa5XmvbEUateQ3bJBEgvLd5kPGAzg1rFkzjVpZJgiKGwvnq5mJpwnbJqcHpVEAopWyALDmtjrDwEvPiTY diff --git a/test/test.py b/test/test.py index cdaf43f2..f5a90c63 100755 --- a/test/test.py +++ b/test/test.py @@ -10,7 +10,7 @@ sys.path.__setitem__(0,os.path.abspath(os.curdir)) import mmgen.config as g import mmgen.opt as opt -from mmgen.util import msgrepr,msgrepr_exit,Msg +from mmgen.util import msgrepr,msgrepr_exit,Msg,die from mmgen.test import * hincog_fn = "rand_data" @@ -21,29 +21,97 @@ hincog_seedlen = 256 incog_id_fn = "incog_id" non_mmgen_fn = "btckey" +ref_dir = os.path.join("test","ref") + +ref_wallet_brainpass = "abc" +ref_wallet_hash_preset = "1" +ref_wallet_incog_offset = 123 + +ref_bw_hash_preset = "1" +ref_bw_file = "brainwallet" +ref_bw_file_spc = "brainwallet-spaced" + +ref_kafile_pass = "kafile password" +ref_kafile_hash_preset = "1" + +ref_enc_fn = "sample-text.mmenc" + cfgs = { '6': { - 'name': "reference wallet check", - 'wallet_label': "test.py reference wallet (password 'abc')", - 'bw_passwd': "abc", - 'bw_hashparams': "256,1", - 'key_id': "98831F3A", - 'addrfile_chk': "6FEF 6FB9 7B13 5D91 854A 0BD3", - 'keyaddrfile_chk': "9F2D D781 1812 8BAD C396 9DEB", + 'name': "reference wallet check (128-bit)", + 'seed_len': 128, + 'seed_id': "FE3C6545", + 'ref_bw_seed_id': "33F10310", + 'addrfile_chk': "B230 7526 638F 38CB 8FDC 8B76", + 'keyaddrfile_chk': "CF83 32FB 8A8B 08E2 0F00 D601", + 'wpasswd': "reference password", + 'ref_wallet': "FE3C6545-D782B529[128,1].mmdat", + 'ic_wallet': "FE3C6545-161E495F-BEB7548E[128:1].incog-offset123", + 'ic_wallet_old': "FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123", - 'wpasswd': "reference password", - 'tmpdir': "test/tmp6", + 'tmpdir': os.path.join("test","tmp6"), 'kapasswd': "", 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses 'dep_generators': { - 'mmdat': "refwalletgen", - 'addrs': "refaddrgen", - 'akeys.mmenc': "refkeyaddrgen" + 'mmdat': "refwalletgen1", + 'addrs': "refaddrgen1", + 'akeys.mmenc': "refkeyaddrgen1" + }, + + }, + '7': { + 'name': "reference wallet check (192-bit)", + 'seed_len': 192, + 'seed_id': "1378FC64", + 'ref_bw_seed_id': "CE918388", + 'addrfile_chk': "8C17 A5FA 0470 6E89 3A87 8182", + 'keyaddrfile_chk': "9648 5132 B98E 3AD9 6FC3 C5AD", + 'wpasswd': "reference password", + 'ref_wallet': "1378FC64-6F0F9BB4[192,1].mmdat", + 'ic_wallet': "1378FC64-B55E9958-77256FC1[192:1].incog.offset123", + 'ic_wallet_old': "1378FC64-B55E9958-D85FF20C[192:1].incog-old.offset123", + + 'tmpdir': os.path.join("test","tmp7"), + 'kapasswd': "", + 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses + 'dep_generators': { + 'mmdat': "refwalletgen2", + 'addrs': "refaddrgen2", + 'akeys.mmenc': "refkeyaddrgen2" + }, + + }, + '8': { + 'name': "reference wallet check (256-bit)", + 'seed_len': 256, + 'seed_id': "98831F3A", + 'ref_bw_seed_id': "B48CD7FC", + 'addrfile_chk': "6FEF 6FB9 7B13 5D91 854A 0BD3", + 'keyaddrfile_chk': "9F2D D781 1812 8BAD C396 9DEB", + 'wpasswd': "reference password", + 'ref_wallet': "98831F3A-27F2BF93[256,1].mmdat", + 'ref_addrfile': "98831F3A[1,31-33,500-501,1010-1011].addrs", + 'ref_keyaddrfile': "98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc", + 'ref_addrfile_chksum': "6FEF 6FB9 7B13 5D91 854A 0BD3", + 'ref_keyaddrfile_chksum': "9F2D D781 1812 8BAD C396 9DEB", + +# 'ref_fake_unspent_data':"98831F3A_unspent.json", + 'ref_tx_file': "tx_FFB367[1.234].raw", + 'ic_wallet': "98831F3A-F59B07A0-559CEF19[256:1].incog.offset123", + 'ic_wallet_old': "98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123", + + 'tmpdir': os.path.join("test","tmp8"), + 'kapasswd': "", + 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses + 'dep_generators': { + 'mmdat': "refwalletgen3", + 'addrs': "refaddrgen3", + 'akeys.mmenc': "refkeyaddrgen3" }, }, '1': { - 'tmpdir': "test/tmp1", + 'tmpdir': os.path.join("test","tmp1"), 'wpasswd': "Dorian", 'kapasswd': "Grok the blockchain", 'addr_idx_list': "12,99,5-10,5,12", # 8 addresses @@ -62,7 +130,7 @@ cfgs = { }, }, '2': { - 'tmpdir': "test/tmp2", + 'tmpdir': os.path.join("test","tmp2"), 'wpasswd': "Hodling away", 'addr_idx_list': "37,45,3-6,22-23", # 8 addresses 'seed_len': 128, @@ -75,7 +143,7 @@ cfgs = { }, }, '3': { - 'tmpdir': "test/tmp3", + 'tmpdir': os.path.join("test","tmp3"), 'wpasswd': "Major miner", 'addr_idx_list': "73,54,1022-1023,2-5", # 8 addresses 'dep_generators': { @@ -86,7 +154,7 @@ cfgs = { }, }, '4': { - 'tmpdir': "test/tmp4", + 'tmpdir': os.path.join("test","tmp4"), 'wpasswd': "Hashrate rising", 'addr_idx_list': "63,1004,542-544,7-9", # 8 addresses 'seed_len': 192, @@ -101,24 +169,24 @@ cfgs = { 'bw_params': "192,1", }, '5': { - 'tmpdir': "test/tmp5", + 'tmpdir': os.path.join("test","tmp5"), 'wpasswd': "My changed password", 'dep_generators': { 'mmdat': "passchg", }, }, '9': { - 'tmpdir': "test/tmp9", + 'tmpdir': os.path.join("test","tmp9"), 'tool_enc_passwd': "Scrypt it, don't hash it!", - 'tool_enc_reftext': + 'sample_text': "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n", 'tool_enc_infn': "tool_encrypt.in", - 'tool_enc_ref_infn': "tool_encrypt_ref.in", +# 'tool_enc_ref_infn': "tool_encrypt_ref.in", 'dep_generators': { 'tool_encrypt.in': "tool_encrypt", 'tool_encrypt.in.mmenc': "tool_encrypt", - 'tool_encrypt_ref.in': "tool_encrypt_ref", - 'tool_encrypt_ref.in.mmenc': "tool_encrypt_ref", +# 'tool_encrypt_ref.in': "tool_encrypt_ref", +# 'tool_encrypt_ref.in.mmenc': "tool_encrypt_ref", }, }, } @@ -126,12 +194,45 @@ cfgs = { from collections import OrderedDict cmd_data = OrderedDict([ # test description depends - ['refwalletgen', (6,'reference wallet seed ID', [[[],6]])], - ['refaddrgen', (6,'reference wallet address checksum', [[["mmdat"],6]])], - ['refkeyaddrgen', (6,'reference wallet key-address checksum', [[["mmdat"],6]])], + # Check saved reference files: + ['ref_wallet_chk1', (6,'saved reference wallet (128-bit)', [[[],6]])], + ['ref_wallet_chk2', (7,'saved reference wallet (192-bit)', [[[],7]])], + ['ref_wallet_chk3', (8,'saved reference wallet (256-bit)', [[[],8]])], + ['ref_seed_chk1', (6,'saved seed file (128-bit)', [[[],6]])], + ['ref_seed_chk2', (7,'saved seed file (192-bit)', [[[],7]])], + ['ref_seed_chk3', (8,'saved seed file (256-bit)', [[[],8]])], + ['ref_mn_chk1', (6,'saved mnemonic file (128-bit)', [[[],6]])], + ['ref_mn_chk2', (7,'saved mnemonic file (192-bit)', [[[],7]])], + ['ref_mn_chk3', (8,'saved mnemonic file (256-bit)', [[[],8]])], + ['ref_incog_chk1', (6,'saved incog reference wallet (128-bit)', [[[],6]])], + ['ref_incog_chk2', (7,'saved incog reference wallet (192-bit)', [[[],7]])], + ['ref_incog_chk3', (8,'saved incog reference wallet (256-bit)', [[[],8]])], + ['ref_brain_chk1', (6,'saved brainwallet (128-bit)', [[[],6]])], + ['ref_brain_chk2', (7,'saved brainwallet (192-bit)', [[[],7]])], + ['ref_brain_chk3', (8,'saved brainwallet (256-bit)', [[[],8]])], + ['ref_brain_chk3_spc', (8,'saved brainwallet (256-bit, non-standard spacing)', [[[],8]])], + + ['ref_addrfile_chk', (8,'saved reference address file', [[[],8]])], + ['ref_keyaddrfile_chk', (8,'saved reference key-address file', [[[],8]])], +# Create the fake inputs: +# ['txcreate8', (8,'transaction creation (8)', [[["addrs"],8]])], + ['ref_tx_chk', (8,'saved reference tx file', [[[],8]])], + + ['ref_tool_decrypt', (9,'decryption of saved MMGen-encrypted file', [[[],9]])], + + # Generate new reference ('abc' brainwallet) files: + ['refwalletgen1', (6,'gen new refwallet (128-bit)', [[[],6]])], + ['refwalletgen2', (7,'gen new refwallet (192-bit)', [[[],7]])], + ['refwalletgen3', (8,'gen new refwallet (256-bit)', [[[],8]])], + ['refaddrgen1', (6,'new refwallet addr chksum (128-bit)', [[["mmdat"],6]])], + ['refaddrgen2', (7,'new refwallet addr chksum (192-bit)', [[["mmdat"],7]])], + ['refaddrgen3', (8,'new refwallet addr chksum (256-bit)', [[["mmdat"],8]])], + ['refkeyaddrgen1', (6,'new refwallet key-addr chksum (128-bit)', [[["mmdat"],6]])], + ['refkeyaddrgen2', (7,'new refwallet key-addr chksum (192-bit)', [[["mmdat"],7]])], + ['refkeyaddrgen3', (8,'new refwallet key-addr chksum (256-bit)', [[["mmdat"],8]])], ['walletgen', (1,'wallet generation', [[[],1]])], - ['walletchk', (1,'wallet check', [[["mmdat"],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]])], @@ -177,10 +278,7 @@ cmd_data = OrderedDict([ ['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)", [[[cfgs['9']['tool_enc_infn'], cfgs['9']['tool_enc_infn']+".mmenc"],9]])], - ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])], - ['tool_decrypt_ref', (9,"'mmgen-tool decrypt' (reference text)", - [[[cfgs['9']['tool_enc_ref_infn'], - cfgs['9']['tool_enc_ref_infn']+".mmenc"],9]])], +# ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])], ['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])], ]) @@ -198,22 +296,28 @@ for k in cfgs.keys(): cfgs[k]['amts'][idx] = "%s.%s" % ((getrandnum(2) % mod), str(getrandnum(4))[:5]) meta_cmds = OrderedDict([ - ['ref', (6,("refwalletgen","refaddrgen","refkeyaddrgen"))], - ['gen', (1,("walletgen","walletchk","addrgen"))], - ['pass', (5,("passchg","walletchk_newpass"))], - ['tx', (1,("txcreate","txsign","txsend"))], + ['saved_ref1', (6,("ref_wallet_chk1","ref_seed_chk1","ref_mn_chk1","ref_brain_chk1","ref_incog_chk1"))], + ['saved_ref2', (7,("ref_wallet_chk2","ref_seed_chk2","ref_mn_chk2","ref_brain_chk2","ref_incog_chk2"))], + ['saved_ref3', (8,("ref_wallet_chk3","ref_seed_chk3","ref_mn_chk3","ref_brain_chk3","ref_incog_chk3","ref_brain_chk3_spc"))], + ['saved_ref_other', (8,("ref_addrfile_chk","ref_tx_chk","ref_tool_decrypt"))], + ['ref1', (6,("refwalletgen1","refaddrgen1","refkeyaddrgen1"))], + ['ref2', (7,("refwalletgen2","refaddrgen2","refkeyaddrgen2"))], + ['ref3', (8,("refwalletgen3","refaddrgen3","refkeyaddrgen3"))], + ['gen', (1,("walletgen","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])], ['online', (1,("keyaddrgen","txsign_keyaddr"))], ['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_find_incog_data"))], + ['tool', (9,("tool_encrypt","tool_decrypt","tool_find_incog_data"))], ]) opts_data = { 'desc': "Test suite for the MMGen suite", - 'usage':"[options] [command or metacommand]", + 'usage':"[options] [command(s) or metacommand(s)]", 'options': """ -h, --help Print this help message -b, --buf-keypress Use buffered keypresses as with real human input @@ -361,10 +465,11 @@ def verify_checksum_or_exit(checksum,chk): class MMGenExpect(object): - def __init__(self,name,mmgen_cmd,cmd_args=[]): + def __init__(self,name,mmgen_cmd,cmd_args=[],extra_desc=""): if not opt.system: mmgen_cmd = os.path.join(os.curdir,mmgen_cmd) desc = cmd_data[name][1] + if extra_desc: desc += " " + extra_desc if opt.verbose or opt.exact_output: sys.stderr.write( green("Testing %s\nExecuting " % desc) + @@ -449,6 +554,9 @@ class MMGenExpect(object): def readline(self): return self.p.readline() + def close(self): + return self.p.close() + def readlines(self): return [l.rstrip()+"\n" for l in self.p.readlines()] @@ -681,17 +789,21 @@ class MMGenTestSuite(object): ok() def refwalletgen(self,name): - label = cfg['wallet_label'] - args = ["-d",cfg['tmpdir'],"-p1","-r10", - "-b"+cfg['bw_hashparams'],"-L",label] + label = "test.py ref. wallet (pw '%s', seed len %s)" \ + % (ref_wallet_brainpass,cfg['seed_len']) + bw_arg = "-b%s,%s" % (cfg['seed_len'], ref_wallet_hash_preset) + args = ["-d",cfg['tmpdir'],"-p1","-r10",bw_arg,"-L",label] + d = " (%s-bit seed)" % cfg['seed_len'] t = MMGenExpect(name,"mmgen-walletgen", args) t.license() t.expect("Type uppercase 'YES' to confirm: ","YES\n") - t.expect("passphrase: ",cfg['bw_passwd']+"\n") + t.expect("passphrase: ",ref_wallet_brainpass+"\n") t.usr_rand(10) t.passphrase_new("new MMGen wallet",cfg['wpasswd']) - key_id = t.written_to_file("Wallet").split("-")[0].split("/")[-1] - refcheck("key id",key_id,cfg['key_id']) + seed_id = t.written_to_file("Wallet").split("-")[0].split("/")[-1] + refcheck("seed id",seed_id,cfg['seed_id']) + + refwalletgen1 = refwalletgen2 = refwalletgen3 = refwalletgen def passchg(self,name,walletfile): @@ -699,7 +811,7 @@ class MMGenTestSuite(object): ["-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.expect_getend("Hash preset changed: ") t.passphrase("MMGen wallet",cfg['wpasswd'],pwtype="new") t.expect("Repeat passphrase: ",cfg['wpasswd']+"\n") t.usr_rand(16) @@ -707,10 +819,6 @@ class MMGenTestSuite(object): t.written_to_file("Wallet") ok() - def walletchk_newpass(self,name,walletfile): - t = self.walletchk_beg(name,[walletfile]) - ok() - def walletchk_beg(self,name,args): t = MMGenExpect(name,"mmgen-walletchk", args) t.expect("Getting MMGen wallet data from file '%s'" % args[-1]) @@ -720,9 +828,11 @@ class MMGenTestSuite(object): return t def walletchk(self,name,walletfile): - t = self.walletchk_beg(name,[walletfile]) + self.walletchk_beg(name,[walletfile]) ok() + walletchk_newpass = walletchk + def addrgen(self,name,walletfile,check_ref=False): t = MMGenExpect(name,"mmgen-addrgen",["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']]) t.license() @@ -737,13 +847,16 @@ class MMGenTestSuite(object): ok() def refaddrgen(self,name,walletfile): + d = " (%s-bit seed)" % cfg['seed_len'] self.addrgen(name,walletfile,check_ref=True) + refaddrgen1 = refaddrgen2 = refaddrgen3 = refaddrgen + def addrimport(self,name,addrfile): outfile = os.path.join(cfg['tmpdir'],"addrfile_w_comments") add_comments_to_addr_file(addrfile,outfile) t = MMGenExpect(name,"mmgen-addrimport",[outfile]) - t.expect_getend(r"checksum for addr data .*\[.*\]: ",regex=True) + t.expect_getend(r"Checksum for address data .*\[.*\]: ",regex=True) t.expect_getend("Validating addresses...OK. ") t.expect("Type uppercase 'YES' to confirm: ","\n") vmsg("This is a simulation, so no addresses were actually imported into the tracking\nwallet") @@ -765,7 +878,7 @@ class MMGenTestSuite(object): ail.add(ai) aix = parse_addr_idxs(cfgs[s]['addr_idx_list']) if len(aix) != addrs_per_wallet: - errmsg(red("Addr index list length != %s: %s" % + errmsg(red("Address index list length != %s: %s" % (addrs_per_wallet,repr(aix)))) sys.exit() tx_data[s] = { @@ -804,7 +917,7 @@ class MMGenTestSuite(object): t.license() for num in tx_data.keys(): t.expect_getend("Getting address data from file ") - chk=t.expect_getend(r"Computed checksum for addr data .*?: ",regex=True) + chk=t.expect_getend(r"Checksum for address data .*?: ",regex=True) verify_checksum_or_exit(tx_data[num]['chk'],chk) # not in tracking wallet warning, (1 + num sources) times @@ -831,13 +944,25 @@ class MMGenTestSuite(object): t.written_to_file("Transaction") ok() - def txsign(self,name,txfile,walletfile): - t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txfile,walletfile]) + def txsign_end(self,t,tnum=None): + t.expect("Signing transaction") + t.expect("Edit transaction comment? (y/N): ","\n") + t.expect("Save signed transaction? (y/N): ","y") + add = " #" + tnum if tnum else "" + t.written_to_file("Signed transaction" + add) + + def txsign(self,name,txfile,walletfile,save=True): + t = MMGenExpect(name,"mmgen-txsign", + ["-d",cfg['tmpdir'],txfile,walletfile]) t.license() t.tx_view() t.passphrase("MMGen wallet",cfg['wpasswd']) - t.expect("Edit transaction comment? (y/N): ","\n") - t.written_to_file("Signed transaction") + if save: + self.txsign_end(t) + else: + t.expect("Edit transaction comment? (y/N): ","\n") + t.expect("Save signed transaction? (y/N): ","\n") + t.expect("Signed transaction not saved") ok() def txsend(self,name,sigfile): @@ -845,10 +970,10 @@ class MMGenTestSuite(object): t.license() t.tx_view() t.expect("Edit transaction comment? (y/N): ","\n") - t.expect("Are you sure you want to broadcast this transaction to the network?") - t.expect("Type uppercase 'YES, I REALLY WANT TO DO THIS' to confirm: ","\n") + t.expect("broadcast this transaction to the network?") + t.expect("'YES, I REALLY WANT TO DO THIS' to confirm: ","\n") t.expect("Exiting at user request") - vmsg("This is a simulation, so no transaction was sent") + vmsg("This is a simulation; no transaction was sent") ok() def export_seed(self,name,walletfile): @@ -943,6 +1068,8 @@ class MMGenTestSuite(object): def refkeyaddrgen(self,name,walletfile): self.keyaddrgen(name,walletfile,check_ref=True) + refkeyaddrgen1 = refkeyaddrgen2 = refkeyaddrgen3 = refkeyaddrgen + def txsign_keyaddr(self,name,keyaddr_file,txfile): t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],"-M",keyaddr_file,txfile]) t.license() @@ -950,9 +1077,7 @@ class MMGenTestSuite(object): t.passphrase("key-address file",cfg['kapasswd']) t.expect("Check key-to-address validity? (y/N): ","y") t.tx_view() - t.expect("Signing transaction...OK") - t.expect("Edit transaction comment? (y/N): ","\n") - t.written_to_file("Signed transaction") + self.txsign_end(t) ok() def walletgen2(self,name): @@ -967,14 +1092,10 @@ class MMGenTestSuite(object): def txsign2(self,name,txf1,wf1,txf2,wf2): t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txf1,wf1,txf2,wf2]) t.license() - - for cnum in ['1','2']: + for cnum in ('1','2'): t.tx_view() t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd']) - t.expect_getend("Signing transaction ") - t.expect("Edit transaction comment? (y/N): ","\n") - t.written_to_file("Signed transaction #%s" % cnum) - + self.txsign_end(t,cnum) ok() def export_mnemonic2(self,name,walletfile): @@ -993,14 +1114,10 @@ class MMGenTestSuite(object): t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],wf1,wf2,txf2]) t.license() t.tx_view() - - for s in ['1','3']: + for cnum in ('1','3'): t.expect_getend("Getting MMGen wallet data from file ") - t.passphrase("MMGen wallet",cfgs[s]['wpasswd']) - - t.expect_getend("Signing transaction") - t.expect("Edit transaction comment? (y/N): ","\n") - t.written_to_file("Signed transaction") + t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd']) + self.txsign_end(t) ok() def walletgen4(self,name): @@ -1019,15 +1136,13 @@ class MMGenTestSuite(object): t.license() t.tx_view() - for cfgnum,what,app in ('1',"incognito"," incognito"),('3',"MMGen",""): + for cnum,what,app in ('1',"incognito"," incognito"),('3',"MMGen",""): t.expect_getend("Getting %s wallet data from file " % what) - t.passphrase("MMGen%s wallet"%app,cfgs[cfgnum]['wpasswd']) - if cfgnum == '1': + t.passphrase("MMGen%s wallet"%app,cfgs[cnum]['wpasswd']) + if cnum == '1': t.hash_preset("incog wallet",'1') - t.expect_getend("Signing transaction") - t.expect("Edit transaction comment? (y/N): ","\n") - t.written_to_file("Signed transaction") + self.txsign_end(t) ok() def tool_encrypt(self,name,infile=""): @@ -1043,11 +1158,11 @@ class MMGenTestSuite(object): t.passphrase_new("user data",cfg['tool_enc_passwd']) t.written_to_file("Encrypted data") ok() - - def tool_encrypt_ref(self,name): - infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn']) - write_to_file(infn,cfg['tool_enc_reftext'],silent=True) - self.tool_encrypt(name,infn) +# Generate the reference mmenc file +# def tool_encrypt_ref(self,name): +# infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn']) +# write_to_file(infn,cfg['tool_enc_reftext'],silent=True) +# self.tool_encrypt(name,infn) def tool_decrypt(self,name,f1,f2): of = name + ".out" @@ -1059,9 +1174,6 @@ class MMGenTestSuite(object): d2 = read_from_file(get_tmpfile_fn(cfg,of)) cmp_or_die(d1,d2) - 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)) @@ -1070,6 +1182,91 @@ class MMGenTestSuite(object): o = t.expect_getend("Incog data for ID \w{8} found at offset ",regex=True) cmp_or_die(hincog_offset,int(o)) + # Saved reference file tests + def ref_wallet_chk(self,name): + wf = os.path.join(ref_dir,cfg['ref_wallet']) + self.walletchk(name,wf) + + ref_wallet_chk1 = ref_wallet_chk2 = ref_wallet_chk3 = ref_wallet_chk + + def ref_seed_chk(self,name,ext=g.seed_ext): + wf = os.path.join(ref_dir,"%s.%s" % (cfg['seed_id'],ext)) + what = "seed data" if ext == g.seed_ext else "mnemonic" + self.keygen_chksum_chk(name,wf,cfg['seed_id'],what) + + ref_seed_chk1 = ref_seed_chk2 = ref_seed_chk3 = ref_seed_chk + + def ref_mn_chk(self,name): self.ref_seed_chk(name,ext=g.mn_ext) + + ref_mn_chk1 = ref_mn_chk2 = ref_mn_chk3 = ref_mn_chk + + def ref_brain_chk(self,name,bw_file=ref_bw_file): + wf = os.path.join(ref_dir,bw_file) + arg = "-b%s,%s" % (cfg['seed_len'],ref_bw_hash_preset) + self.keygen_chksum_chk(name,wf,cfg['ref_bw_seed_id'],"brainwallet",[arg]) + + def keygen_chksum_chk(self,name,wf,seed_id,what,args=[]): + t = MMGenExpect(name,"mmgen-keygen", ["-q","-A"]+args+[wf,"1"]) + chk = t.expect_getend("Valid %s for seed ID " % what) + t.close() + cmp_or_die(seed_id,chk) + + ref_brain_chk1 = ref_brain_chk2 = ref_brain_chk3 = ref_brain_chk + + def ref_brain_chk3_spc(self,name): + self.ref_brain_chk(name,bw_file=ref_bw_file_spc) + + def ref_incog_chk(self,name): + for wtype,desc,earg in ('ic_wallet','',[]), \ + ('ic_wallet_old','(old format)',["-o"]): + ic_arg = "%s,%s,%s" % ( + os.path.join(ref_dir,cfg[wtype]), + ref_wallet_incog_offset,cfg['seed_len'] + ) + t = MMGenExpect(name,"mmgen-keygen", + ["-q","-A"]+earg+["-G"]+[ic_arg]+['1'],extra_desc=desc) + t.passphrase("MMGen incognito wallet",cfg['wpasswd']) + t.hash_preset("incog wallet","1") + if wtype == 'ic_wallet_old': + t.expect("Is the seed ID correct? (Y/n): ","\n") + chk = t.expect_getend("Valid incog data for seed ID ") + t.close() + cmp_or_die(cfg['seed_id'],chk) + + ref_incog_chk1 = ref_incog_chk2 = ref_incog_chk3 = ref_incog_chk + + def ref_addrfile_chk(self,name,ftype="addr"): + wf = os.path.join(ref_dir,cfg['ref_'+ftype+'file']) + t = MMGenExpect(name,"mmgen-tool",[ftype+"file_chksum",wf]) + if ftype == "keyaddr": + w = "key-address file" + t.hash_preset(w,ref_kafile_hash_preset) + t.passphrase(w,ref_kafile_pass) + t.expect("Check key-to-address validity? (y/N): ","y") + o = t.expect_getend("Checksum for .*address data .*: ",regex=True) + cmp_or_die(cfg['ref_'+ftype+'file_chksum'],o) + + def ref_keyaddrfile_chk(self,name): + self.ref_addrfile_chk(name,ftype="keyaddr") + +# def txcreate8(self,name,addrfile): +# self.txcreate_common(name,sources=['8']) + + def ref_tx_chk(self,name): + tf = os.path.join(ref_dir,cfg['ref_tx_file']) + wf = os.path.join(ref_dir,cfg['ref_wallet']) + self.txsign(name,tf,wf,save=False) + + def ref_tool_decrypt(self,name): + f = os.path.join(ref_dir,ref_enc_fn) + t = MMGenExpect(name,"mmgen-tool", + ["-q","decrypt",f,"outfile=-","hash_preset=1"]) + t.passphrase("user data",cfg['tool_enc_passwd']) + t.readline() + import re + o = re.sub('\r\n','\n',t.read()) + cmp_or_die(cfg['sample_text'],o) + # main() if opt.pause: import termios,atexit @@ -1086,26 +1283,17 @@ for cfg in sorted(cfgs): mk_tmpdir(cfgs[cfg]) try: if cmd_args: - arg1 = cmd_args[0] - if arg1 in utils: - globals()[arg1](cmd_args[1:]) - sys.exit() - elif arg1 in meta_cmds: - if len(cmd_args) == 1: - for cmd in meta_cmds[arg1][1]: + for arg in cmd_args: + if arg in utils: + globals()[arg](cmd_args[cmd_args.index(arg)+1:]) + sys.exit() + elif arg in meta_cmds: + for cmd in meta_cmds[arg][1]: check_needs_rerun(ts,cmd,build=True,force_delete=True) + elif arg in cmd_data: + check_needs_rerun(ts,arg,build=True) else: - msg("Only one meta command may be specified") - sys.exit(1) - elif arg1 in cmd_data.keys(): - if len(cmd_args) == 1: - check_needs_rerun(ts,arg1,build=True) - else: - msg("Only one command may be specified") - sys.exit(1) - else: - errmsg("%s: unrecognized command" % arg1) - sys.exit(1) + die(1,"%s: unrecognized command" % arg) else: clean() for cmd in cmd_data: