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.
This commit is contained in:
philemon 2015-04-07 17:57:17 +03:00
commit 4a93cdee6a
42 changed files with 561 additions and 267 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:
""",

View file

@ -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] <address range or list>",
'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","")

View file

@ -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))

View file

@ -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")

View file

@ -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] <command> <command args>",
'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)

View file

@ -17,8 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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] <addr,amt> ... [change addr] [addr file] ...",
@ -55,7 +57,7 @@ of the form <seed ID>:<number>.
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

View file

@ -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] <signed transaction file>",
'options': """
-h, --help Print this help message

View file

@ -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] <transaction file> .. [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-<what> 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)

View file

@ -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

View file

@ -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-<what>' 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)

View file

@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------------------
# 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.

View file

@ -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)

View file

@ -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)

View file

@ -17,7 +17,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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)

View file

@ -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", ['<MMGen tx file> [str]','pager [bool=False]','terse [bool=False]']),
("txview", ['<{pnm} tx file> [str]','pager [bool=False]','terse [bool=False]'.format(pnm=pnm)]),
("addrfile_chksum", ['<MMGen addr file> [str]']),
("keyaddrfile_chksum", ['<MMGen addr file> [str]']),
("addrfile_chksum", ['<{pnm} addr file> [str]'.format(pnm=pnm)]),
("keyaddrfile_chksum", ['<{pnm} addr file> [str]'.format(pnm=pnm)]),
("find_incog_data", ['<file or device name> [str]','<Incog ID> [str]','keep_searching [bool=False]']),
("encrypt", ['<infile> [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)

View file

@ -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")

View file

@ -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

View file

@ -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

1
test/ref/1378FC64.mmseed Normal file
View file

@ -0,0 +1 @@
6bbc91 7L6o G2dR nAFk hncM Q7TU 8Gcc CEGP oKxx C

View file

@ -0,0 +1 @@
duck memory screen world knee thank pray ignore physical season sanity anymore view prince fix compare mother make

View file

@ -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

1
test/ref/98831F3A.mmseed Normal file
View file

@ -0,0 +1 @@
3f96a4 5g1y LZ2a wULJ mffJ BkuG 4b1j w4RX u6V5 9Q5A XQg9 tPtd

View file

@ -0,0 +1 @@
dry satisfy pure admire around realize balance sentence husband weary dew trail desk velvet effort strange quite throw morning family drawn exactly block core

View file

@ -0,0 +1,19 @@
# MMGen address file
#
# This file is editable.
# Everything following a hash symbol '#' is a comment and ignored by MMGen.
# A text label of 32 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.
# Address data checksum for 98831F3A[1,31-33,500-501,1010-1011]: 6FEF 6FB9 7B13 5D91 854A 0BD3
# Record this value to a secure location
98831F3A {
1 1MU7EdgqYy9JX35L25hR6CmXXcSEBDAwyv
31 1Kb8npGGTVtm5qf6Gik4WdLgQoznwufEc "#$%&()*+,- ./09:;<=>?@AZ[]_az|'
32 19X3wLG3m7Dg6o5bppk1eqwkLiLVSJ8t1H
33 177t1mCffzMWihi9w2Jbb9MQ331zFTxmDJ
500 1EZNuddPnaZFah9QVbGvzvTcP4KeRrRFt8
501 1ET1CZJtXZanLqbGhFkd4h1hsHengakjqV
1010 1DysuxsnRA46wd9bpFhLog2jwtpARmP6BY
1011 1DD7mfGAPWme3p8f52AJA9rNQ2SxV1ZUe6
}

View file

@ -0,0 +1,6 @@
.O¡ÎQe‚%S°)Àl[Ës!ÞÖŒ÷JÚU·zê¤]\q}²ä—Èjmçö ²Yr‚Ù¡M_/_³Q�#6„Þ·�¿Æ=˜›gzÈœEƒ<•sTíó�éL©ª#� õGóGöß="eÆ£h÷ªS†€y)–å`æúâmAI® ð¸j=tŽ91Ä„‘ŸnêYãdüȾå&FëO½ÞáèD~hE9ÃYòOyϪç»J‹iÝ}È+·8ÇtS`b&ƒÑ|� «†BR©¤yÑò`üI;=ã}§ƒ:_„]?†hÇñ#!ŸÊm÷º1� ëeïC_+u;nxÌ)˜À�ýñ¢–g
Í­Íšð’ƒ…œ�mÁ¼a :‚¾ØÉâ±�†…~Aà÷§7ý 7ÿYî�t#Jô´ßµàÒ\_‘}¼¢ ¹^£/…;ŠÈw•à ×XŠÕ ö°§À9˜
‘%&´sVWÀ~T"Ç}°–ý¼Vp êˆ�EÍ*ÎOjÚÆÑHoY�–DG£ìÑu¹¿9[e�Œå`Õ©©¶OÎØÞCøT¶û�ôí<A~;Û�ÎØápbEöä8ü�=4�¢Ið¬$ii”&eݧOZ˜ c3Gß9mð¼¹�Ôñ˜ãr9n�©7c…7¬=nß\åØÄ²®ývüà·bJô®¦zìâÕ¶YlØvTi,Ù‚@>·Ë²ÎÝ ©9‚ÆzT ž',ħašþZÝ8_´N£Q± ·æ™Uø§€Þа’¡¶?ûÝM‚/ËjP_ ÚÝ�ÂXën0Ëéâü¾ÔƒÜoï‡ ÔÖ§'+Ú?ÆöL6HÑn�w>¥º¢éˆH|\ž+3ÏI,Ϋf–HL�%°PÛ¡î_`‹ë�~,2vÝö”üáhäYÁÿíAMd‚®WÌ8¬%H¶Ç�LEÒ†�©×nüÀ•ÐÈ¥v´lêj�Q_�`'‹¯<¯Fg�„WŸu: ) Æ#‡ægíWÛ“áèÃ!Wl÷‘�]�]»õÍ´&H Ž@©sÁ¡«¦=ô[\^?¦$ˆ´)ò%E, â’3�YßD$à”ÖgNo‡e0×Ïðé9¶Ô…-½<•سà¢Õáß®#¬H·[áwh¦@D3ŸãÒb@ÃYKà`—OÚª YG‡³ 8[pYf½�,ræ�_/öþ�A“^‘VŸ?l¼ó°±¬4ÿÅñCQý'Yç¨ �‹œ˜‚¬¼6œ
È
ŽC5z^EPmWA$þµI›Äq‘u׸§03Ê¡)I‘p¥^X†Áô²$¢<F›™ûÌ‹å�éR�½=^²ÜXE¢i]ÈõI

View file

@ -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

1
test/ref/FE3C6545.mmseed Normal file
View file

@ -0,0 +1 @@
0e6d52 9aFM LL5z pLA7 DNLu vAha hT

View file

@ -0,0 +1 @@
dude foot desperate tie stood themselves trip descend cease suicide apple busy

1
test/ref/brainwallet Normal file
View file

@ -0,0 +1 @@
A brainwallet with some non-standard spacing

View file

@ -0,0 +1,11 @@
A
brainwallet
with some
non-standard
spacing

View file

@ -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

View file

@ -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: