Improved options handling, some files moved and renamed.

Users who are upgrading must delete the 'opt' directory in their previous
installation before installing.  On a Linux system, this is typically
located at:

	/usr/local/lib/python2.7/dist-packages/mmgen/opt
This commit is contained in:
The MMGen Project 2015-01-10 18:52:30 +03:00
commit c7056a7ba2
28 changed files with 542 additions and 481 deletions

View file

@ -30,6 +30,7 @@ from mmgen.bitcoin import numtowif
from mmgen.util import *
from mmgen.tx import is_mmgen_idx,is_mmgen_seed_id,is_btc_addr,is_wif,get_wif2addr_f
import mmgen.config as g
import mmgen.opt as opt
addrmsgs = {
'addrfile_header': """
@ -60,13 +61,13 @@ def test_for_keyconv():
return True
def generate_addrs(seed, addrnums, opts):
def generate_addrs(seed, addrnums):
from util import make_chksum_8
seed_id = make_chksum_8(seed) # Must do this before seed gets clobbered
if 'a' in opts['gen_what']:
if g.no_keyconv or test_for_keyconv() == False:
if 'a' in opt.gen_what:
if opt.no_keyconv or test_for_keyconv() == False:
msg("Using (slow) internal ECDSA library for address generation")
from mmgen.bitcoin import privnum2addr
keyconv = False
@ -81,7 +82,7 @@ def generate_addrs(seed, addrnums, opts):
'ka': ('key/address pair','s'),
'k': ('key','s'),
'a': ('address','es')
}[opts['gen_what']]
}[opt.gen_what]
from mmgen.addr import AddrInfoEntry,AddrInfo
@ -89,7 +90,7 @@ def generate_addrs(seed, addrnums, opts):
seed = sha512(seed).digest()
num += 1 # round
if g.debug: print "Seed round %s: %s" % (num, hexlify(seed))
if opt.debug: print "Seed round %s: %s" % (num, hexlify(seed))
if num != addrnums[pos]: continue
pos += 1
@ -103,20 +104,20 @@ def generate_addrs(seed, addrnums, opts):
sec = sha256(sha256(seed).digest()).hexdigest()
wif = numtowif(int(sec,16))
if 'a' in opts['gen_what']:
if 'a' in opt.gen_what:
if keyconv:
e.addr = check_output([keyconv, wif]).split()[1]
else:
e.addr = privnum2addr(int(sec,16))
if 'k' in opts['gen_what']: e.wif = wif
if 'b16' in opts: e.sec = sec
if 'k' in opt.gen_what: e.wif = wif
if opt.b16: e.sec = sec
out.append(e)
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 opts['gen_what'])
a = AddrInfo(has_keys='k' in opt.gen_what)
a.initialize(seed_id,out)
return a

View file

@ -21,23 +21,38 @@ config.py: Constants and configuration options for the MMGen suite
"""
import sys, os
prog_name = os.path.basename(sys.argv[0])
author = "Philemon"
email = "<mmgen-py@yandex.com>"
Cdates = '2013-2015'
version = '0.7.9'
# Variables - these might be altered at runtime:
quiet,verbose,no_keyconv = False,False,False
user_entropy = ""
hash_preset = '3'
usr_randchars = 30
use_urandchars = False
min_screen_width = 80
max_tx_comment_len = 72
# returns None if env var unset
debug = os.getenv("MMGEN_DEBUG")
no_license = os.getenv("MMGEN_NOLICENSE")
bogus_wallet_data = os.getenv("MMGEN_BOGUS_WALLET_DATA")
disable_hold_protect = os.getenv("MMGEN_DISABLE_HOLD_PROTECT")
from decimal import Decimal
tx_fee = Decimal("0.00005")
max_tx_fee = Decimal("0.01")
proj_name = "MMGen"
seed_len = 256
http_timeout = 30
# Constants - these don't change at runtime
proj_name = "MMGen"
prog_name = os.path.basename(sys.argv[0])
author = "Philemon"
email = "<mmgen-py@yandex.com>"
Cdates = '2013-2015'
version = '0.7.9'
min_screen_width = 80
max_tx_comment_len = 72
wallet_ext = "mmdat"
seed_ext = "mmseed"
@ -48,49 +63,37 @@ incog_hex_ext = "mmincox"
seedfile_exts = wallet_ext, seed_ext, mn_ext, brain_ext, incog_ext
rawtx_ext = "raw"
sigtx_ext = "sig"
addrfile_ext = "addrs"
rawtx_ext = "raw"
sigtx_ext = "sig"
addrfile_ext = "addrs"
addrfile_chksum_ext = "chk"
keyfile_ext = "keys"
keyaddrfile_ext = "akeys"
mmenc_ext = "mmenc"
keyfile_ext = "keys"
keyaddrfile_ext = "akeys"
mmenc_ext = "mmenc"
default_wl = "electrum"
#default_wl = "tirosh"
# Global value sets user opt
dfl_vars = "seed_len","hash_preset"
# If user opt is set, different global opt is set to 'True'
usr_set_vars = { "usr_randchars": "use_urandchars" }
# User opt sets global value
usr_set_vars = "no_keyconv","verbose","quiet","usr_randchars"
# Global value sets user opt
dfl_vars = "seed_len","hash_preset","usr_randchars","debug"
seed_lens = 128,192,256
seed_len = 256
mn_lens = [i / 32 * 3 for i in seed_lens]
http_timeout = 30
keyconv_exec = "keyconv"
# returns None if env var unset
debug = os.getenv("MMGEN_DEBUG")
no_license = os.getenv("MMGEN_NOLICENSE")
bogus_wallet_data = os.getenv("MMGEN_BOGUS_WALLET_DATA")
disable_hold_protect = os.getenv("MMGEN_DISABLE_HOLD_PROTECT")
mins_per_block = 8.5
mins_per_block = 8.5
passwd_max_tries = 5
usr_randchars = 30
max_urandchars,min_urandchars = 80,10
use_urandchars = False
salt_len = 16
aesctr_iv_len = 16
salt_len = 16
aesctr_iv_len = 16
hash_preset = '3'
hash_presets = {
# Scrypt params:
# ID N p r
@ -114,7 +117,6 @@ max_addr_label_len = 32
wallet_label_symbols = addr_label_symbols
max_wallet_label_len = 32
user_entropy = ""
#addr_label_punc = ".","_",",","-"," ","(",")"
#addr_label_symbols = tuple(ascii_letters + digits) + addr_label_punc
#wallet_label_punc = addr_label_punc

View file

@ -25,6 +25,7 @@ from binascii import hexlify
from hashlib import sha256
import mmgen.config as g
import mmgen.opt as opt
from mmgen.util import *
from mmgen.term import get_char
@ -77,7 +78,7 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
if compare_checksums(chk2,"of decrypted seed",seed_id,"in header"):
qmsg("Passphrase is OK")
else:
if not g.debug:
if not opt.debug:
msg_r("Checking key ID...")
if compare_checksums(chk1, "of key", key_id, "in header"):
msg("Key ID is correct but decryption of seed failed")
@ -89,7 +90,7 @@ def decrypt_seed(enc_seed, key, seed_id, key_id):
# else:
# qmsg("Generated IDs (Seed/Key): %s/%s" % (chk2,chk1))
if g.debug: print "Decrypted seed: %s" % hexlify(dec_seed)
if opt.debug: print "Decrypted seed: %s" % hexlify(dec_seed)
vmsg("OK")
return dec_seed
@ -153,18 +154,18 @@ def make_key(passwd,salt,hash_preset,
what="encryption key",from_what="passphrase",verbose=False):
if from_what: what += " from "
if g.verbose or verbose:
if opt.verbose or verbose:
msg_r("Generating %s%s.\nPlease wait..." % (what,from_what))
key = scrypt_hash_passphrase(passwd, salt, hash_preset)
if g.verbose or verbose:
if opt.verbose or verbose:
msg("done")
if g.debug: print "Key: %s" % hexlify(key)
if opt.debug: print "Key: %s" % hexlify(key)
return key
def get_random_data_from_user(uchars):
if g.quiet: msg("Enter %s random symbols" % uchars)
if opt.quiet: msg("Enter %s random symbols" % uchars)
else: msg(crmsg['usr_rand_notice'] % uchars)
prompt = "You may begin typing. %s symbols left: "
@ -184,12 +185,12 @@ def get_random_data_from_user(uchars):
time_data.append(now - saved_time)
saved_time = now
if g.quiet: msg_r("\r")
if opt.quiet: msg_r("\r")
else: msg_r("\rThank you. That's enough.%s\n\n" % (" "*18))
fmt_time_data = ["{:.22f}".format(i) for i in time_data]
if g.debug:
if opt.debug:
msg("\nUser input:\n%s\nKeystroke time intervals:\n%s\n" %
(key_data,"\n".join(fmt_time_data)))
@ -206,7 +207,7 @@ def get_random(length):
from_what = "OS random data"
if not g.user_entropy:
g.user_entropy = \
sha256(get_random_data_from_user(g.usr_randchars)).digest()
sha256(get_random_data_from_user(opt.usr_randchars)).digest()
from_what += " plus user-supplied entropy"
else:
from_what += " plus saved user-supplied entropy"
@ -218,7 +219,6 @@ def get_random(length):
def get_seed_from_wallet(
infile,
opts,
prompt_info="{} wallet".format(g.proj_name),
silent=False
):
@ -226,22 +226,22 @@ def get_seed_from_wallet(
wdata = get_data_from_wallet(infile,silent=silent)
label,metadata,hash_preset,salt,enc_seed = wdata
if g.debug: display_control_data(*wdata)
if opt.debug: display_control_data(*wdata)
padd = " "+infile if g.quiet else ""
passwd = get_mmgen_passphrase(prompt_info+padd,opts)
padd = " "+infile if opt.quiet else ""
passwd = get_mmgen_passphrase(prompt_info+padd)
key = make_key(passwd, salt, hash_preset)
return decrypt_seed(enc_seed, key, metadata[0], metadata[1])
def get_hidden_incog_data(opts):
def get_hidden_incog_data():
# Already sanity-checked:
fname,offset,seed_len = opts['from_incog_hidden'].split(",")
fname,offset,seed_len = opt.from_incog_hidden.split(",")
qmsg("Getting hidden incog data from file '%s'" % fname)
z = 0 if 'old_incog_fmt' in opts else 8
z = 0 if opt.old_incog_fmt else 8
dlen = g.aesctr_iv_len + g.salt_len + (int(seed_len)/8) + z
fsize = check_data_fits_file_at_offset(fname,int(offset),dlen,"read")
@ -265,13 +265,12 @@ def confirm_old_format():
elif reply in 'nN': msg("\nExiting at user request"); sys.exit(1)
elif reply in 'mM': msg(""); return True
else:
if g.verbose: msg("\nInvalid reply")
if opt.verbose: msg("\nInvalid reply")
else: msg_r("\r")
def get_seed_from_incog_wallet(
infile,
opts,
prompt_info="{} incognito wallet".format(g.proj_name),
silent=False,
hex_input=False
@ -279,8 +278,8 @@ def get_seed_from_incog_wallet(
what = "incognito wallet data"
if "from_incog_hidden" in opts:
d = get_hidden_incog_data(opts)
if opt.from_incog_hidden:
d = get_hidden_incog_data()
else:
d = get_data_from_file(infile,what)
if hex_input:
@ -290,7 +289,7 @@ def get_seed_from_incog_wallet(
msg("Data in file '%s' is not in hexadecimal format" % infile)
sys.exit(2)
# File could be of invalid length, so check:
z = 0 if 'old_incog_fmt' in opts else 8
z = 0 if opt.old_incog_fmt else 8
valid_dlens = [i/8 + g.aesctr_iv_len + g.salt_len + z for i in g.seed_lens]
# New fmt: [56, 64, 72]. Old fmt: [48, 56, 64].
if len(d) not in valid_dlens:
@ -308,11 +307,11 @@ 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.")
vmsg(crmsg['incog_iv_id_hidden' if "from_incog_hidden" in opts
vmsg(crmsg['incog_iv_id_hidden' if opt.from_incog_hidden
else 'incog_iv_id'])
while True:
passwd = get_mmgen_passphrase(prompt_info+" "+incog_id,opts)
passwd = get_mmgen_passphrase(prompt_info+" "+incog_id)
qmsg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets)))
hp = get_hash_preset_from_user(what="incog wallet")
@ -333,7 +332,7 @@ def get_seed_from_incog_wallet(
m = "Seed ID: %s. Is the Seed ID correct?" % sid
return keypress_confirm(m, True)
if 'old_incog_fmt' in opts:
if opt.old_incog_fmt:
if confirm_correct_seed_id(old_fmt_sid):
break
else:
@ -349,7 +348,7 @@ def get_seed_from_incog_wallet(
return seed
def _get_seed(infile,opts,silent=False,seed_id=""):
def _get_seed(infile,silent=False,seed_id=""):
ext = get_extension(infile)
@ -359,10 +358,10 @@ def _get_seed(infile,opts,silent=False,seed_id=""):
elif ext == g.wallet_ext: source = "wallet"
elif ext == g.incog_ext: source = "incognito wallet"
elif ext == g.incog_hex_ext: source = "incognito wallet"
elif 'from_mnemonic' in opts: source = "mnemonic"
elif 'from_brain' in opts: source = "brainwallet"
elif 'from_seed' in opts: source = "seed"
elif 'from_incog' in opts: source = "incognito wallet"
elif opt.from_mnemonic : source = "mnemonic"
elif opt.from_brain : source = "brainwallet"
elif opt.from_seed : source = "seed"
elif opt.from_incog : source = "incognito wallet"
else:
if infile: msg(
"Invalid file extension for file: %s\nValid extensions: '.%s'" %
@ -373,26 +372,26 @@ def _get_seed(infile,opts,silent=False,seed_id=""):
seed_id_str = " for seed ID "+seed_id if seed_id else ""
if source == "mnemonic":
prompt = "Enter mnemonic%s: " % seed_id_str
words = get_words(infile,"mnemonic data",prompt,opts)
words = get_words(infile,"mnemonic data",prompt)
wl = get_default_wordlist()
from mmgen.mnemonic import get_seed_from_mnemonic
seed = get_seed_from_mnemonic(words,wl)
elif source == "brainwallet":
if 'from_brain' not in opts:
if not opt.from_brain:
msg("'--from-brain' parameters must be specified for brainwallet file")
sys.exit(2)
prompt = "Enter brainwallet passphrase%s: " % seed_id_str
words = get_words(infile,"brainwallet data",prompt,opts)
seed = _get_seed_from_brain_passphrase(words,opts)
words = get_words(infile,"brainwallet data",prompt)
seed = _get_seed_from_brain_passphrase(words)
elif source == "seed":
prompt = "Enter seed%s in %s format: " % (seed_id_str,g.seed_ext)
words = get_words(infile,"seed data",prompt,opts)
words = get_words(infile,"seed data",prompt)
seed = get_seed_from_seed_data(words)
elif source == "wallet":
seed = get_seed_from_wallet(infile, opts, silent=silent)
seed = get_seed_from_wallet(infile, silent=silent)
elif source == "incognito wallet":
h = ext == g.incog_hex_ext or 'from_incog_hex' in opts
seed = get_seed_from_incog_wallet(infile, opts, silent=silent, hex_input=h)
h = (ext == g.incog_hex_ext) or opt.from_incog_hex
seed = get_seed_from_incog_wallet(infile, silent=silent, hex_input=h)
if infile and not seed and (
@ -400,25 +399,25 @@ def _get_seed(infile,opts,silent=False,seed_id=""):
msg("Invalid %s file '%s'" % (source,infile))
sys.exit(2)
if g.debug: print "Seed: %s" % hexlify(seed)
if opt.debug: print "Seed: %s" % hexlify(seed)
return seed
# Repeat if entered data is invalid
def get_seed_retry(infile,opts,seed_id=""):
def get_seed_retry(infile,seed_id=""):
silent = False
while True:
seed = _get_seed(infile,opts,silent=silent,seed_id=seed_id)
seed = _get_seed(infile,silent=silent,seed_id=seed_id)
silent = True
if seed: return seed
def _get_seed_from_brain_passphrase(words,opts):
def _get_seed_from_brain_passphrase(words):
bp = " ".join(words)
if g.debug: print "Sanitized brain passphrase: %s" % bp
seed_len,hash_preset = get_from_brain_opt_params(opts)
if g.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset)
if opt.debug: print "Sanitized brain passphrase: %s" % bp
seed_len,hash_preset = get_from_brain_opt_params()
if opt.debug: print "Brainwallet l = %s, p = %s" % (seed_len,hash_preset)
vmsg_r("Hashing brainwallet data. Please wait...")
# Use buflen arg of scrypt.hash() to get seed of desired length
seed = scrypt_hash_passphrase(bp, "", hash_preset, buflen=seed_len/8)
@ -429,7 +428,7 @@ def _get_seed_from_brain_passphrase(words,opts):
# Vars for mmgen_*crypt functions only
salt_len,sha256_len,nonce_len = 32,32,32
def mmgen_encrypt(data,what="data",hash_preset='',opts={}):
def mmgen_encrypt(data,what="data",hash_preset=''):
salt,iv,nonce = get_random(salt_len),\
get_random(g.aesctr_iv_len), \
get_random(nonce_len)
@ -451,7 +450,7 @@ def mmgen_decrypt(data,what="data",hash_preset=""):
hp = hash_preset or get_hash_preset_from_user('3',what)
m = "default" if hp == '3' else "user-requested"
qmsg("Using %s hash preset of '%s'" % (m,hp))
passwd = get_mmgen_passphrase(what,{})
passwd = get_mmgen_passphrase(what)
key = make_key(passwd, salt, hp)
dec_d = decrypt_data(enc_d, key, int(hexlify(iv),16), what)
if dec_d[:sha256_len] == sha256(dec_d[sha256_len:]).digest():

View file

@ -24,6 +24,7 @@ import sys
from mmgen.util import msg, msg_r
from mmgen.term import get_char
import mmgen.config as g
import mmgen.opt as opt
gpl = {
'warning': """
@ -589,7 +590,7 @@ copy of the Program in return for a fee.
def do_license_msg(immed=False):
if g.quiet or g.no_license: return
if opt.quiet or g.no_license: return
msg(gpl['warning'])
prompt = "%s " % gpl['prompt'].strip()

View file

@ -24,7 +24,7 @@ mmgen-addrgen: Generate a series or range of addresses from an MMGen
import sys
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.license import *
from mmgen.util import *
from mmgen.crypto import *
@ -32,8 +32,7 @@ from mmgen.addr import *
what = "keys" if sys.argv[0].split("-")[-1] == "keygen" else "addresses"
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': """Generate a range or list of {} from an {g.proj_name} wallet,
mnemonic, seed or password""".format(what,g=g),
'usage':"[opts] [infile] <address range or list>",
@ -114,25 +113,24 @@ UNENCRYPTED form. Generate only the key(s) you need and guard them carefully.
""".format(g.proj_name),
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data,add_opts=["b16"])
if 'show_hash_presets' in opts: show_hash_presets()
if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
opts['from_incog'] = True
if opt.show_hash_presets: show_hash_presets()
if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args)
if len(cmd_args) == 1 and (
'from_mnemonic' in opts
or 'from_brain' in opts
or 'from_seed' in opts
or 'from_incog_hidden' in opts
opt.from_mnemonic
or opt.from_brain
or opt.from_seed
or opt.from_incog_hidden
):
infile,addr_idx_arg = "",cmd_args[0]
elif len(cmd_args) == 2:
infile,addr_idx_arg = cmd_args
check_infile(infile)
else: usage(help_data)
else: opt.opts.usage(opts_data)
addr_idxs = parse_addr_idxs(addr_idx_arg)
@ -141,46 +139,46 @@ if not addr_idxs: sys.exit(2)
do_license_msg()
# Interact with user:
if what == "keys" and not g.quiet:
if what == "keys" and not opt.quiet:
confirm_or_exit(wmsg['unencrypted_secret_keys'], 'continue')
# Generate data:
seed = get_seed_retry(infile,opts)
seed = get_seed_retry(infile)
opts['gen_what'] = "a" if what == "addresses" else (
"k" if 'no_addresses' in opts else "ka")
opt.gen_what = "a" if what == "addresses" else (
"k" if opt.no_addresses else "ka")
ainfo = generate_addrs(seed, addr_idxs, opts)
ainfo = generate_addrs(seed, addr_idxs)
addrdata_str = ainfo.fmt_data()
outfile_base = "{}[{}]".format(make_chksum_8(seed), ainfo.idxs_fmt)
if 'a' in opts['gen_what']:
w = "key-address" if 'k' in opts['gen_what'] else "address"
if 'a' in opt.gen_what:
w = "key-address" if 'k' in opt.gen_what else "address"
qmsg("Checksum for %s data %s: %s" % (w,outfile_base,ainfo.checksum))
if 'save_checksum' in opts:
if opt.save_checksum:
write_to_file(outfile_base+"."+g.addrfile_chksum_ext,
ainfo.checksum+"\n",opts,"%s data checksum" % w,True,True,False)
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.")
if 'k' in opts['gen_what'] and keypress_confirm("Encrypt key list?"):
addrdata_str = mmgen_encrypt(addrdata_str,"new key list","",opts)
if 'k' in opt.gen_what and keypress_confirm("Encrypt key list?"):
addrdata_str = mmgen_encrypt(addrdata_str,"new key list","")
enc_ext = "." + g.mmenc_ext
else: enc_ext = ""
# Output data:
if 'stdout' in opts or not sys.stdout.isatty():
if opt.stdout or not sys.stdout.isatty():
if enc_ext and sys.stdout.isatty():
msg("Cannot write encrypted data to screen. Exiting")
sys.exit(2)
write_to_stdout(addrdata_str,what,
(what=="keys"and not g.quiet and sys.stdout.isatty()))
(what=="keys"and not opt.quiet and sys.stdout.isatty()))
else:
outfile = "%s.%s%s" % (outfile_base, (
g.keyaddrfile_ext if "ka" in opts['gen_what'] else (
g.keyfile_ext if "k" in opts['gen_what'] else
g.keyaddrfile_ext if "ka" in opt.gen_what else (
g.keyfile_ext if "k" in opt.gen_what else
g.addrfile_ext)), enc_ext)
write_to_file(outfile,addrdata_str,opts,what,not g.quiet,True)
write_to_file(outfile,addrdata_str,what,not opt.quiet,True)

View file

@ -21,14 +21,14 @@ mmgen-addrimport: Import addresses into a MMGen bitcoind tracking wallet
"""
import sys, time
from mmgen.Opts import *
import mmgen.config as g
import mmgen.opt as opt
from mmgen.license import *
from mmgen.util import *
from mmgen.tx import connect_to_bitcoind
from mmgen.addr import AddrInfo,AddrInfoEntry
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': """Import addresses (both {pnm} and non-{pnm}) into a bitcoind
tracking wallet""".format(pnm=g.proj_name),
'usage':"[opts] [mmgen address file]",
@ -47,12 +47,12 @@ in the tracking wallet.
"""
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if len(cmd_args) == 1:
infile = cmd_args[0]
check_infile(infile)
if 'addrlist' in opts:
if opt.addrlist:
lines = get_lines_from_file(
infile,"non-{} addresses".format(g.proj_name),trim_comments=True)
ai,adata = AddrInfo(),[]
@ -62,7 +62,7 @@ if len(cmd_args) == 1:
adata.append(a)
ai.initialize(None,adata)
else:
ai = AddrInfo(infile,has_keys='keyaddr_file' in opts)
ai = AddrInfo(infile,has_keys=opt.keyaddr_file)
else:
msg("""
"You must specify an mmgen address file (or a list of non-%s addresses
@ -80,10 +80,9 @@ for e in ai.addrdata:
m = (" from seed ID %s" % ai.seed_id) if ai.seed_id else ""
qmsg("OK. %s addresses%s" % (ai.num_addrs,m))
import mmgen.config as g
g.http_timeout = 3600
if not 'test' in opts:
if not opt.test:
c = connect_to_bitcoind()
m = """
@ -92,30 +91,30 @@ necessary only if an address you're importing is already on the blockchain,
has a balance and is not already in your tracking wallet. Note that the
rescanning process is very slow (>30 min. for each imported address on a
low-powered computer).
""".strip() if "rescan" in opts else """
""".strip() if opt.rescan else """
WARNING: If any of the addresses you're importing is already on the blockchain,
has a balance and is not already in your tracking wallet, you must exit the
program now and rerun it using the '--rescan' option. Otherwise you may ignore
this message and continue.
""".strip()
if g.quiet: m = ""
if opt.quiet: m = ""
confirm_or_exit(m, "continue", expect="YES")
err_flag = False
def import_address(addr,label,rescan):
try:
if not 'test' in opts:
if not opt.test:
c.importaddress(addr,label,rescan)
except:
global err_flag
err_flag = True
w_n_of_m = len(str(ai.num_addrs)) * 2 + 2
w_mmid = "" if 'addrlist' in opts else len(str(max(ai.idxs()))) + 12
w_mmid = "" if opt.addrlist else len(str(max(ai.idxs()))) + 12
if "rescan" in opts:
if opt.rescan:
import threading
msg_fmt = "\r%s %-{}s %-34s %s".format(w_n_of_m)
else:
@ -128,7 +127,7 @@ for n,e in enumerate(ai.addrdata):
if e.comment: label += " " + e.comment
else: label = "non-%s" % g.proj_name
if "rescan" in opts:
if opt.rescan:
t = threading.Thread(target=import_address, args=(e.addr,label,True))
t.daemon = True
t.start()

View file

@ -22,13 +22,12 @@ mmgen-passchg: Change an MMGen deterministic wallet's passphrase, label or
"""
import sys
from mmgen.Opts import *
from mmgen.util import *
from mmgen.crypto import *
import mmgen.config as g
import mmgen.opt as opt
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': """Change the passphrase, hash preset or label of an {}
deterministic wallet""".format(g.proj_name),
'usage': "[opts] [filename]",
@ -55,9 +54,9 @@ NOTE: The key ID will change if either the passphrase or hash preset are
"""
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if 'show_hash_presets' in opts: show_hash_presets()
if opt.show_hash_presets: show_hash_presets()
if len(cmd_args) != 1:
msg("One input file must be specified")
@ -71,36 +70,36 @@ seed_id,key_id = metadata[:2]
# Repeat on incorrect pw entry
while True:
p = "{} wallet".format(g.proj_name)
passwd = get_mmgen_passphrase(p,{},not 'keep_old_passphrase' in opts)
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)
if seed: break
changed = {}
if 'label' in opts:
if opts['label'] != label:
msg("Label changed: '%s' -> '%s'" % (label, opts['label']))
if opt.label:
if opt.label != label:
msg("Label changed: '%s' -> '%s'" % (label, opt.label))
changed['label'] = True
else:
msg("Label is unchanged: '%s'" % (label))
else: opts['label'] = label # Copy the old label
else: opt.label = label # Copy the old label
if 'hash_preset' in opts:
if hash_preset != opts['hash_preset']:
if opt.hash_preset:
if hash_preset != opt.hash_preset:
qmsg("Hash preset has changed (%s -> %s)" %
(hash_preset, opts['hash_preset']))
(hash_preset, opt.hash_preset))
changed['preset'] = True
else:
msg("Hash preset is unchanged")
else:
opts['hash_preset'] = hash_preset
opt.hash_preset = hash_preset
if 'keep_old_passphrase' in opts:
if opt.keep_old_passphrase:
msg("Keeping old passphrase by user request")
else:
new_passwd = get_new_passphrase(
"{} wallet".format(g.proj_name), opts, True)
"{} wallet".format(g.proj_name), True)
if new_passwd == passwd:
qmsg("Passphrase is unchanged")
@ -115,7 +114,7 @@ if 'preset' in changed or 'passwd' in changed: # Update key ID, salt
from hashlib import sha256
salt = sha256(salt + get_random(128)).digest()[:g.salt_len]
key = make_key(passwd, salt, opts['hash_preset'])
key = make_key(passwd, salt, opt.hash_preset)
new_key_id = make_chksum_8(key)
qmsg("Key ID changed: %s -> %s" % (key_id,new_key_id))
key_id = new_key_id
@ -124,4 +123,4 @@ elif not 'label' in changed:
msg("Data unchanged. No file will be written")
sys.exit(2)
write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts)
write_wallet_to_file(seed, passwd, key_id, salt, enc_seed)

View file

@ -23,11 +23,10 @@ mmgen-tool: Perform various MMGen- and Bitcoin-related operations.
import sys
import mmgen.config as g
import mmgen.opt as opt
import mmgen.tool as tool
from mmgen.Opts import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Perform various MMGen- and Bitcoin-related operations",
'usage': "[opts] <command> <command args>",
'options': """
@ -46,10 +45,10 @@ command
""".format(tool.cmd_help,g.prog_name)
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if len(cmd_args) < 1:
usage(help_data)
opt.opts.usage(opts_data)
sys.exit(1)
command = cmd_args.pop(0)
@ -64,6 +63,4 @@ if cmd_args and cmd_args[0] == '--help':
args,kwargs = tool.process_args(g.prog_name, command, cmd_args)
tool.opts = opts
tool.__dict__[command](*args,**kwargs)

View file

@ -25,12 +25,11 @@ import sys
from decimal import Decimal
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.license import *
from mmgen.tx import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Create a BTC transaction with outputs to specified addresses",
'usage': "[opts] <addr,amt> ... [change addr] [addr file] ...",
'options': """
@ -124,7 +123,7 @@ def format_unspent_outputs_for_printing(out,sort_info,total):
)
def sort_and_view(unspent,opts):
def sort_and_view(unspent):
def s_amt(i): return i.amount
def s_txid(i): return "%s %03s" % (i.txid,i.vout)
@ -239,7 +238,7 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
elif reply == 'p':
d = format_unspent_outputs_for_printing(unsp,sort_info,total)
of = "listunspent[%s].out" % ",".join(sort_info)
write_to_file(of, d, opts,"",False,False)
write_to_file(of, d, "",False,False)
write_to_file_msg = "Data written to '%s'\n\n" % of
elif reply == 'v':
do_pager("\n".join(out))
@ -333,16 +332,16 @@ def mmaddr2btcaddr(c,mmaddr,acct_data,ail):
return btcaddr
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if opt.debug: show_opts_and_cmd_args(cmd_args)
if 'comment_file' in opts:
comment = get_tx_comment_from_file(opts['comment_file'])
if opt.comment_file:
comment = get_tx_comment_from_file(opt.comment_file)
c = connect_to_bitcoind()
if not 'info' in opts:
if not opt.info:
do_license_msg(immed=True)
tx_out,acct_data,change_addr = {},{},""
@ -389,30 +388,31 @@ if not 'info' in opts:
msg("At least one output must be specified on the command line")
sys.exit(2)
tx_fee = opts['tx_fee'] if 'tx_fee' in opts else g.tx_fee
tx_fee = opt.tx_fee if opt.tx_fee else g.tx_fee
tx_fee = normalize_btc_amt(tx_fee)
if tx_fee > g.max_tx_fee:
msg("Transaction fee too large: %s > %s" % (tx_fee,g.max_tx_fee))
sys.exit(2)
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if opt.debug: show_opts_and_cmd_args(cmd_args)
if g.bogus_wallet_data: # for debugging purposes only
import mmgen.rpc.data
us = eval(get_data_from_file(g.bogus_wallet_data))
else:
us = c.listunspent()
# write_to_file("bogus_unspent.json", repr(us), opts); sys.exit()
# write_to_file("bogus_unspent.json", repr(us)); sys.exit()
if not us: msg(wmsg['no_spendable_outputs']); sys.exit(2)
for o in us:
o.mmid,o.comment = parse_mmgen_label(o.account)
del o.account
unspent = sort_and_view(us,opts)
unspent = sort_and_view(us)
total = trim_exponent(sum([i.amount for i in unspent]))
msg("Total unspent: %s BTC (%s outputs)" % (total, len(unspent)))
if 'info' in opts: sys.exit(0)
if opt.info: sys.exit(0)
send_amt = sum([tx_out[i] for i in tx_out.keys()])
msg("Total amount to spend: %s%s" % (
@ -458,11 +458,11 @@ if change > 0: tx_out[change_addr] = float(change)
tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent]
if g.debug:
if opt.debug:
print "tx_in:", repr(tx_in)
print "tx_out:", repr(tx_out)
if 'comment_file' in opts:
if opt.comment_file:
if keypress_confirm("Edit comment?",False):
comment = get_tx_comment_from_user(comment)
else:
@ -493,6 +493,6 @@ if keypress_confirm("Save transaction?",default_yes=False):
outfile = "tx_%s[%s].%s" % (tx_id,amt,g.rawtx_ext)
data = make_tx_data("{} {} {}".format(*metadata),
tx_hex,sel_unspent,b2m_map,comment)
write_to_file(outfile,data,opts,"transaction",False,True)
write_to_file(outfile,data,"transaction",False,True)
else:
msg("Transaction not saved")

View file

@ -23,13 +23,12 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
import sys
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.license import *
from mmgen.tx import *
from mmgen.util import msg,check_infile,get_lines_from_file,confirm_or_exit
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Send a Bitcoin transaction signed by {}-txsign".format(g.proj_name.lower()),
'usage': "[opts] <signed transaction file>",
'options': """
@ -39,11 +38,11 @@ help_data = {
"""
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if len(cmd_args) == 1:
infile = cmd_args[0]; check_infile(infile)
else: usage(help_data)
else: opt.opts.usage(opts_data)
# Begin execution
@ -66,13 +65,13 @@ if keypress_confirm("Edit transaction comment?"):
inputs_data, b2m_map, comment)
w = "signed transaction with edited comment"
outfile = infile
write_to_file(outfile,data,opts,w,False,True,True)
write_to_file(outfile,data,w,False,True,True)
warn = "Once this transaction is sent, there's no taking it back!"
what = "broadcast this transaction to the network"
expect = "YES, I REALLY WANT TO DO THIS"
if g.quiet: warn,expect = "","YES"
if opt.quiet: warn,expect = "","YES"
confirm_or_exit(warn, what, expect)
@ -87,4 +86,4 @@ except:
msg("Transaction sent: %s" % tx_id)
of = "tx_{}[{}].txid".format(*metadata[:2])
write_to_file(of, tx_id+"\n",opts,"transaction ID",True,True)
write_to_file(of, tx_id+"\n","transaction ID",True,True)

View file

@ -23,12 +23,11 @@ mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate'
import sys
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.license import *
from mmgen.tx import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Sign Bitcoin transactions generated by {}-txcreate".format(g.proj_name.lower()),
'usage': "[opts] <transaction file> .. [mmgen wallet/seed/words/brainwallet file] ..",
'options': """
@ -103,7 +102,7 @@ Removed %s duplicate wif key%s from keylist (also in {MMG} key-address file
""".strip().format(MMG=g.proj_name),
}
def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts):
def get_seed_for_seed_id(seed_id,infiles,saved_seeds):
if seed_id in saved_seeds.keys():
return saved_seeds[seed_id]
@ -112,11 +111,10 @@ def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts):
while True:
if infiles:
seed = get_seed_retry(infiles.pop(0),opts)
elif "from_brain" in opts or "from_mnemonic" in opts \
or "from_seed" in opts or "from_incog" in opts:
seed = get_seed_retry(infiles.pop(0))
elif opt.from_brain or opt.from_mnemonic or opt.from_seed or opt.from_incog:
qmsg("Need seed data for seed ID %s" % seed_id)
seed = get_seed_retry("",opts,seed_id)
seed = get_seed_retry("",seed_id)
msg("User input produced seed ID %s" % make_chksum_8(seed))
else:
msg("ERROR: No seed source found for seed ID: %s" % seed_id)
@ -128,7 +126,7 @@ def get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts):
if sid == seed_id: return seed
def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts):
def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds):
seed_ids = set([i[:8] for i in mmgen_addrs])
vmsg("Need seed%s: %s" % (suf(seed_ids,"k")," ".join(seed_ids)))
@ -137,9 +135,10 @@ def get_keys_for_mmgen_addrs(mmgen_addrs,infiles,saved_seeds,opts):
from mmgen.addr import generate_addrs
for seed_id in seed_ids:
# Returns only if seed is found
seed = get_seed_for_seed_id(seed_id,infiles,saved_seeds,opts)
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]
ai = generate_addrs(seed,addr_nums,{'gen_what':"ka"})
opt.gen_what = "ka"
ai = generate_addrs(seed,addr_nums)
d += [("{}:{}".format(seed_id,e.idx),e.addr,e.wif) for e in ai.addrdata]
return d
@ -148,7 +147,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None):
if keys:
qmsg("Passing %s key%s to bitcoind" % (len(keys),suf(keys,"k")))
if g.debug: print "Keys:\n %s" % "\n ".join(keys)
if opt.debug: print "Keys:\n %s" % "\n ".join(keys)
msg_r("Signing transaction{}...".format(tx_num_str))
from mmgen.rpc import exceptions
@ -161,7 +160,7 @@ def sign_transaction(c,tx_hex,tx_num_str,sig_data,keys=None):
return sig_tx
def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts):
def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys):
try:
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
@ -170,7 +169,7 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts):
msg("Using keys in wallet.dat as per user request")
prompt = "Enter passphrase for bitcoind wallet: "
while True:
passwd = get_bitcoind_passphrase(prompt,opts)
passwd = get_bitcoind_passphrase(prompt)
try:
c.walletpassphrase(passwd, 9999)
@ -190,11 +189,11 @@ def sign_tx_with_bitcoind_wallet(c,tx_hex,tx_num_str,sig_data,keys,opts):
return sig_tx
def check_maps_from_seeds(maplist,label,infiles,saved_seeds,opts,return_keys=False):
def check_maps_from_seeds(maplist,label,infiles,saved_seeds,return_keys=False):
if not maplist: return []
qmsg("Checking MMGen -> BTC address mappings for %ss (from seeds)" % label)
d = get_keys_for_mmgen_addrs(maplist.keys(),infiles,saved_seeds,opts)
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])
for a,b in zip(sorted(m),sorted(maplist)):
@ -214,9 +213,9 @@ for the following non-{} address{}:\n {}""".format(
g.proj_name,suf(addrs,"a"),"\n ".join(addrs)).strip()
def parse_mmgen_keyaddr_file(opts):
def parse_mmgen_keyaddr_file():
from mmgen.addr import AddrInfo
ai = AddrInfo(opts['mmgen_keys_from_file'],has_keys=True)
ai = AddrInfo(opt.mmgen_keys_from_file,has_keys=True)
vmsg("Found %s wif key%s for seed ID %s" %
(ai.num_addrs, suf(ai.num_addrs,"k"), ai.seed_id))
# idx: (0=addr, 1=comment 2=wif) -> mmaddr: (0=addr, 1=wif)
@ -224,8 +223,8 @@ def parse_mmgen_keyaddr_file(opts):
[("%s:%s"%(ai.seed_id,e.idx), (e.addr,e.wif)) for e in ai.addrdata])
def parse_keylist(opts,from_file):
fn = opts['keys_from_file']
def parse_keylist(from_file):
fn = opt.keys_from_file
d = get_data_from_file(fn,"non-%s keylist" % g.proj_name)
enc_ext = get_extension(fn) == g.mmenc_ext
if enc_ext or not is_utf8(d):
@ -279,17 +278,16 @@ def get_keys_from_keylist(kldata,other_addrs):
return ret
opts,infiles = parse_opts(sys.argv,help_data)
infiles = opt.opts.init(opts_data,add_opts=["b16"])
for l in (
('tx_id', 'info'),
('tx_id', 'terse_info'),
): warn_incompatible_opts(opts,l)
): opt.opts.warn_incompatible_opts(l)
if 'from_incog_hex' in opts or 'from_incog_hidden' in opts:
opts['from_incog'] = True
if opt.from_incog_hex or opt.from_incog_hidden: opt.from_incog = True
if not infiles: usage(help_data)
if not infiles: opt.opts.usage(opts_data)
for i in infiles: check_infile(i)
c = connect_to_bitcoind()
@ -298,14 +296,14 @@ saved_seeds = {}
tx_files = [i for i in infiles if get_extension(i) == g.rawtx_ext]
seed_files = [i for i in infiles if get_extension(i) != g.rawtx_ext]
if not "info" in opts and not "terse_info" in opts:
if not opt.info and not opt.terse_info:
do_license_msg(immed=True)
from_file = { 'mmdata':{}, 'kldata':{} }
if 'mmgen_keys_from_file' in opts:
from_file['mmdata'] = parse_mmgen_keyaddr_file(opts) or {}
if 'keys_from_file' in opts:
from_file['kldata'] = parse_keylist(opts,from_file) or {}
if opt.mmgen_keys_from_file:
from_file['mmdata'] = parse_mmgen_keyaddr_file() or {}
if opt.keys_from_file:
from_file['kldata'] = parse_keylist(from_file) or {}
tx_num_str = ""
for tx_num,tx_file in enumerate(tx_files,1):
@ -313,19 +311,19 @@ for tx_num,tx_file in enumerate(tx_files,1):
msg("\nTransaction #%s of %s:" % (tx_num,len(tx_files)))
tx_num_str = " #%s" % tx_num
m = "" if 'tx_id' in opts else "transaction data"
m = "" if opt.tx_id else "transaction data"
tx_data = get_lines_from_file(tx_file,m)
metadata,tx_hex,inputs_data,b2m_map,comment = parse_tx_file(tx_data,tx_file)
vmsg("Successfully opened transaction file '%s'" % tx_file)
if 'tx_id' in opts:
if opt.tx_id:
msg(metadata[0])
sys.exit(0)
if 'info' in opts or 'terse_info' in opts:
if opt.info or opt.terse_info:
view_tx_data(c,inputs_data,tx_hex,b2m_map,comment,metadata,pause=False,
terse='terse_info' in opts)
terse=opt.terse_info)
sys.exit(0)
prompt_and_view_tx_data(c,"View data for transaction{}?".format(tx_num_str),
@ -336,7 +334,7 @@ for tx_num,tx_file in enumerate(tx_files,1):
keys = get_keys_from_keylist(from_file['kldata'],other_addrs)
if other_addrs and not 'use_wallet_dat' in opts:
if other_addrs and not opt.use_wallet_dat:
missing_keys_errormsg(other_addrs)
sys.exit(2)
@ -347,8 +345,8 @@ for tx_num,tx_file in enumerate(tx_files,1):
keys += check_maps_from_kafile(imap,"input",from_file['mmdata'],True)
check_maps_from_kafile(omap,"output",from_file['mmdata'])
keys += check_maps_from_seeds(imap,"input",seed_files,saved_seeds,opts,True)
check_maps_from_seeds(omap,"output",seed_files,saved_seeds,opts)
keys += check_maps_from_seeds(imap,"input",seed_files,saved_seeds,True)
check_maps_from_seeds(omap,"output",seed_files,saved_seeds)
extra_sids = set(saved_seeds.keys()) - sids
if extra_sids:
@ -360,9 +358,9 @@ for tx_num,tx_file in enumerate(tx_files,1):
{"txid":i['txid'],"vout":i['vout'],"scriptPubKey":i['scriptPubKey']}
for i in inputs_data]
if 'use_wallet_dat' in opts:
if opt.use_wallet_dat:
sig_tx = sign_tx_with_bitcoind_wallet(
c,tx_hex,tx_num_str,sig_data,keys,opts)
c,tx_hex,tx_num_str,sig_data,keys)
else:
sig_tx = sign_transaction(c,tx_hex,tx_num_str,sig_data,keys)
@ -374,7 +372,7 @@ 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,opts,w,(not g.quiet),True,False)
write_to_file(outfile,data,w,(not opt.quiet),True,False)
else:
msg_r("failed\nSome keys were missing. ")
msg("Transaction %scould not be signed." % tx_num_str)

View file

@ -23,12 +23,11 @@ mmgen-walletchk: Check integrity of an MMGen deterministic wallet, display
import sys
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.util import *
from mmgen.crypto import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': """Check integrity of an {} deterministic wallet, display
its information, and export seed and mnemonic data.
""".format(g.proj_name),
@ -61,14 +60,14 @@ to disable this option, then specify '-r0' on the command line.
"""
}
def wallet_to_incog_data(infile,opts):
def wallet_to_incog_data(infile):
d = get_data_from_wallet(infile,silent=True)
seed_id,key_id,preset,salt,enc_seed = \
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),opts)
passwd = get_mmgen_passphrase("{} wallet".format(g.proj_name))
key = make_key(passwd, salt, preset, "main key")
seed = decrypt_seed(enc_seed, key, seed_id, key_id)
if seed: break
@ -77,7 +76,7 @@ def wallet_to_incog_data(infile,opts):
iv_id = make_iv_chksum(iv)
msg("Incog ID: %s" % iv_id)
if not 'old_incog_fmt' in opts:
if not opt.old_incog_fmt:
salt = get_random(g.salt_len)
key = make_key(passwd, salt, preset, "incog wallet key")
key_id = make_chksum_8(key)
@ -92,13 +91,13 @@ def wallet_to_incog_data(infile,opts):
return iv+wrap_enc,seed_id,key_id,iv_id,preset
def export_to_hidden_incog(incog_enc,opts):
outfile,offset = opts['export_incog_hidden'].split(",") #Already sanity-checked
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
def export_to_hidden_incog(incog_enc):
outfile,offset = opt.export_incog_hidden.split(",") #Already sanity-checked
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
check_data_fits_file_at_offset(outfile,int(offset),len(incog_enc),"write")
if not g.quiet: confirm_or_exit("","alter file '%s'" % outfile)
if not opt.quiet: confirm_or_exit("","alter file '%s'" % outfile)
import os
f = os.open(outfile,os.O_RDWR)
os.lseek(f, int(offset), os.SEEK_SET)
@ -108,60 +107,60 @@ def export_to_hidden_incog(incog_enc,opts):
(os.path.relpath(outfile),offset))
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if 'export_incog_hidden' in opts or 'export_incog_hex' in opts:
opts['export_incog'] = True
if opt.export_incog_hidden or opt.export_incog_hex:
opt.export_incog = True
if len(cmd_args) != 1: usage(help_data)
if len(cmd_args) != 1: opt.opts.usage(opts_data)
check_infile(cmd_args[0])
if set(['outdir','export_incog_hidden']) <= set(opts.keys()):
if opt.outdir and opt.export_incog_hidden:
msg("Warning: '--outdir' option is ignored when exporting hidden incog data")
g.use_urandchars = True
if 'export_mnemonic' in opts:
if opt.export_mnemonic:
qmsg("Exporting mnemonic data to file by user request")
elif 'export_seed' in opts:
elif opt.export_seed:
qmsg("Exporting seed data to file by user request")
elif 'export_incog' in opts:
elif opt.export_incog:
qmsg("Exporting wallet to incognito format by user request")
incog_enc,seed_id,key_id,iv_id,preset = \
wallet_to_incog_data(cmd_args[0],opts)
wallet_to_incog_data(cmd_args[0])
if "export_incog_hidden" in opts:
export_to_hidden_incog(incog_enc,opts)
if opt.export_incog_hidden:
export_to_hidden_incog(incog_enc)
else:
z = 0 if 'old_incog_fmt' in opts else 8
z = 0 if opt.old_incog_fmt else 8
seed_len = (len(incog_enc)-g.salt_len-g.aesctr_iv_len-z)*8
fn = "%s-%s-%s[%s,%s].%s" % (
seed_id, key_id, iv_id, seed_len, preset,
g.incog_hex_ext if "export_incog_hex" in opts else g.incog_ext
g.incog_hex_ext if opt.export_incog_hex else g.incog_ext
)
data = pretty_hexdump(incog_enc,2,8,line_nums=False) \
if "export_incog_hex" in opts else incog_enc
write_to_file_or_stdout(fn, data, opts, "incognito wallet data")
if opt.export_incog_hex else incog_enc
write_to_file_or_stdout(fn, data, "incognito wallet data")
sys.exit()
seed = get_seed_retry(cmd_args[0], opts)
seed = get_seed_retry(cmd_args[0])
if seed: msg("Wallet is OK")
else:
msg("Error opening wallet")
sys.exit(2)
if 'export_mnemonic' in opts:
if opt.export_mnemonic:
wl = get_default_wordlist()
from mmgen.mnemonic import get_mnemonic_from_seed
mn = get_mnemonic_from_seed(seed, wl, g.default_wl, g.debug)
mn = get_mnemonic_from_seed(seed, wl, g.default_wl, opt.debug)
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.mn_ext)
write_to_file_or_stdout(fn, " ".join(mn)+"\n", opts, "mnemonic data")
write_to_file_or_stdout(fn, " ".join(mn)+"\n", "mnemonic data")
elif 'export_seed' in opts:
elif opt.export_seed:
from mmgen.bitcoin import b58encode_pad
data = col4(b58encode_pad(seed))
chk = make_chksum_6(b58encode_pad(seed))
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.seed_ext)
write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), opts, "seed data")
write_to_file_or_stdout(fn, "%s %s\n" % (chk,data), "seed data")

View file

@ -24,13 +24,12 @@ import sys, os
from hashlib import sha256
import mmgen.config as g
from mmgen.Opts import *
import mmgen.opt as opt
from mmgen.license import *
from mmgen.util import *
from mmgen.crypto import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Generate an {} deterministic wallet".format(g.proj_name),
'usage': "[opts] [infile]",
'options': """
@ -121,11 +120,12 @@ future, you must continue using these same parameters
""",
}
opts,cmd_args = parse_opts(sys.argv,help_data)
import mmgen.opt as opt
cmd_args = opt.opts.init(opts_data)
if 'show_hash_presets' in opts: show_hash_presets()
if opt.show_hash_presets: show_hash_presets()
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if opt.debug: opt.opts.show_opts_and_cmd_args(cmd_args)
if len(cmd_args) == 1:
infile = cmd_args[0]
@ -140,7 +140,7 @@ if len(cmd_args) == 1:
sys.exit(1)
elif len(cmd_args) == 0:
infile = ""
else: usage(help_data)
else: opt.opts.usage(opts_data)
g.use_urandchars = True
@ -148,31 +148,27 @@ g.use_urandchars = True
do_license_msg()
if 'from_brain' in opts and not g.quiet:
if opt.from_brain and not opt.quiet:
confirm_or_exit(wmsg['brain_warning'].format(
g.proj_name, *get_from_brain_opt_params(opts)),
g.proj_name, *get_from_brain_opt_params()),
"continue")
for i in 'from_mnemonic','from_brain','from_seed','from_incog':
if infile or (i in opts):
seed = get_seed_retry(infile,opts)
# if "from_incog" in opts or get_extension(infile) == g.incog_ext:
# qmsg(cmessages['incog'] % make_chksum_8(seed))
# else: qmsg("")
qmsg("")
break
if infile or (opt.from_mnemonic or opt.from_brain
or opt.from_seed or opt.from_incog):
seed = get_seed_retry(infile)
qmsg("")
else:
# Truncate random data for smaller seed lengths
seed = sha256(get_random(128)).digest()[:opts['seed_len']/8]
seed = sha256(get_random(128)).digest()[:opt.seed_len/8]
salt = sha256(get_random(128)).digest()[:g.salt_len]
qmsg(wmsg['choose_wallet_passphrase'] % opts['hash_preset'])
qmsg(wmsg['choose_wallet_passphrase'] % opt.hash_preset)
passwd = get_new_passphrase("new {} wallet".format(g.proj_name), opts)
passwd = get_new_passphrase("new {} wallet".format(g.proj_name))
key = make_key(passwd, salt, opts['hash_preset'])
key = make_key(passwd, salt, opt.hash_preset)
enc_seed = encrypt_seed(seed, key)
write_wallet_to_file(seed,passwd,make_chksum_8(key),salt,enc_seed,opts)
write_wallet_to_file(seed,passwd,make_chksum_8(key),salt,enc_seed)

View file

@ -25,6 +25,7 @@ from binascii import hexlify
from mmgen.util import msg,msg_r,make_chksum_8,Vmsg
from mmgen.crypto import get_random
import mmgen.config as g
import mmgen.opt as opt
wl_checksums = {
"electrum": '5ca31424',

22
mmgen/opt.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C)2013-2015 Philemon <mmgen-py@yandex.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
opt.py: an empty namespace for the global opt variables
"""
import opts

View file

@ -17,15 +17,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Opts.py: Option handling routines for the MMGen suite
opts.py: Further options processing after mmgen.share.Opts
"""
import sys
import mmgen.config as g
import mmgen.opt.Opts
from mmgen.util import msg,check_infile,check_outfile,check_outdir,msgrepr_exit,msgrepr
def usage(hd): mmgen.opt.Opts.usage(hd)
import mmgen.config as g
import mmgen.share.Opts
import opt
from mmgen.util import msg,msgrepr_exit,msgrepr
def usage(opts_data):
print "USAGE: %s %s" % (opts_data['prog_name'], opts_data['usage'])
sys.exit(2)
def print_version_info():
print """
@ -33,19 +36,38 @@ def print_version_info():
Copyright (C) {g.Cdates} by {g.author} {g.email}.
""".format(g=g).strip()
def warn_incompatible_opts(opts,incompat_list):
bad = [k for k in opts.keys() if k in incompat_list]
def warn_incompatible_opts(incompat_list):
bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in incompat_list]
if len(bad) > 1:
msg("Mutually exclusive options: %s" % " ".join(
["--"+b.replace("_","-") for b in bad]))
sys.exit(1)
def parse_opts(argv,help_data):
def typeconvert_from_dfl(opts,opt):
if len(argv) == 2 and argv[1] == '--version':
vtype = type(g.__dict__[opt])
if g.debug: print "Override opt: %-15s [%s]" % (opt,vtype)
try:
opts[opt] = vtype(opts[opt])
except:
d = {
'int': 'an integer',
'str': 'a string',
'float': 'a float',
'bool': 'a boolean value',
}
m = [d[k] for k in d if __builtins__[k] == vtype][0]
msg("'%s': invalid parameter for '--%s' option (not %s)" %
(opts[opt],opt.replace("_","-"),m))
sys.exit(1)
def init(opts_data,add_opts=[]):
if len(sys.argv) == 2 and sys.argv[1] == '--version':
print_version_info(); sys.exit()
opts,args,short_opts,long_opts = mmgen.opt.Opts.parse_opts(argv,help_data)
opts,args,short_opts,long_opts = mmgen.share.Opts.parse_opts(sys.argv,opts_data)
if g.debug:
print "short opts: %s" % repr(short_opts)
@ -53,46 +75,58 @@ def parse_opts(argv,help_data):
print "user-selected opts: %s" % repr(opts)
print "cmd args: %s" % repr(args)
# check opts without modifying them
if not check_opts(opts,long_opts): sys.exit(1)
# If user opt is set, an opt in mmgen.config is set to 'True'
for v in g.usr_set_vars:
if v in opts:
g.__dict__[g.usr_set_vars[v]] = True
# If user opt is unset, set it to default value in mmgen.config (g):
# If set, convert its type based on value in mmgen.config
for v in g.dfl_vars:
if v in opts: typeconvert_from_dfl(opts,v)
else: opts[v] = g.__dict__[v]
if g.debug: print "opts after typeconvert: %s" % opts
# A hack, but harmless
extra_opts = [
"quiet","verbose","debug",
"outdir","echo_passphrase","passwd_file"
] + add_opts
# Transfer opts into our custom namespace
for o in [s.rstrip("=") for s in long_opts] + extra_opts:
opt.__dict__[o] = opts[o] if o in opts else None
for l in (
('from_incog_hidden','from_incog','from_seed','from_mnemonic','from_brain'),
('export_incog','export_incog_hex','export_incog_hidden','export_mnemonic',
'export_seed'),
('quiet','verbose')
): warn_incompatible_opts(opts,l)
): warn_incompatible_opts(l)
if 'usr_randchars' in opts: g.use_urandchars = True
del mmgen.share.Opts
return args
# check opts[] dictionary without modifying it
if not check_opts(opts,long_opts): sys.exit(1)
def show_opts_and_cmd_args(cmd_args):
print "Processed options:"
d = opt.__dict__
for k in d:
if k[:2] != "__" and k != "opts" and d[k] != None:
msg("%-20s: %s" % (k, d[k]))
print "Cmd args: %s" % repr(cmd_args)
# If user opt is unset, set it to default value in mmgen.config (g):
for v in g.dfl_vars:
if v in opts: typeconvert_override_var(opts,v)
else: opts[v] = g.__dict__[v]
def show_all_opts():
msg("Processed options:")
d = opt.__dict__
for k in d:
if k[:2] != "__" and k != "opts":
msg("%-20s: %s" % (k, d[k]))
# Opposite of above: set the value in mmgen.config (g) from user opt:
for k in g.usr_set_vars:
if k in opts:
v = opts[k]
try: v = type(g.__dict__[k])(v)
except:
msg(
"Argument '%s' for option '--%s' cannot be converted to target type %s" %
(v,k.replace("_","-"),type(g.__dict__[k]))
)
sys.exit(1)
g.__dict__[k] = v
if g.debug: print "opts after typeconvert: %s" % opts
return opts,args
def show_opts_and_cmd_args(opts,cmd_args):
print "Processed options: %s" % repr(opts)
print "Cmd args: %s" % repr(cmd_args)
def check_opts(opts,long_opts):
def check_opts(opts,long_opts): # Returns false if any check fails
def opt_splits(val,sep,n,what):
sepword = "comma" if sep == "," else (
@ -136,10 +170,12 @@ def check_opts(opts,long_opts):
# Check for file existence and readability
if opt in ('keys_from_file','mmgen_keys_from_file',
'passwd_file','keysforaddrs','comment_file'):
from mmgen.util import check_infile
check_infile(val) # exits on error
continue
if opt == 'outdir':
from mmgen.util import check_outdir
check_outdir(val) # exits on error
elif opt == 'label':
if not opt_compares(len(val),"<=",g.max_wallet_label_len,"label length"):
@ -155,11 +191,13 @@ def check_opts(opts,long_opts):
if opt == 'from_incog_hidden':
if not opt_splits(val,",",3,what): return False
infile,offset,seed_len = val.split(",")
from mmgen.util import check_infile
check_infile(infile)
w = "seed length " + what
if not opt_is_int(seed_len,w): return False
if not opt_is_in_list(int(seed_len),g.seed_lens,w): return False
else:
from mmgen.util import check_outfile
if not opt_splits(val,",",2,what): return False
outfile,offset = val.split(",")
check_outfile(outfile)
@ -184,24 +222,6 @@ def check_opts(opts,long_opts):
if not opt_compares(val,">=",g.min_urandchars,what): return False
if not opt_compares(val,"<=",g.max_urandchars,what): return False
else:
if g.debug: print "check_opts(): No test for opt '%s'" % opt
if 'debug' in opts: print "check_opts(): No test for opt '%s'" % opt
return True
def typeconvert_override_var(opts,opt):
vtype = type(eval("g."+opt))
if g.debug: print "Override opt: %-15s [%s]" % (opt,vtype)
if vtype == int: f,t = int,"an integer"
elif vtype == str: f,t = str,"a string"
elif vtype == float: f,t = float,"a float"
elif vtype == bool: f,t = bool,"a boolean value"
try:
opts[opt] = f(opts[opt])
except:
msg("'%s': invalid parameter for '--%s' option (not %s)" %
(opts[opt],opt.replace("_","-"),t))
sys.exit(1)

View file

@ -18,23 +18,25 @@
import sys, getopt
def usage(hd):
print "USAGE: %s %s" % (hd['prog_name'], hd['usage'])
def usage(opts_data):
print "USAGE: %s %s" % (opts_data['prog_name'], opts_data['usage'])
sys.exit(2)
def print_help(help_data):
pn = help_data['prog_name']
def print_help(opts_data):
pn = opts_data['prog_name']
pn_len = str(len(pn)+2)
print (" %-"+pn_len+"s %s") % (pn.upper()+":", help_data['desc'].strip())
print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, help_data['usage'].strip())
print (" %-"+pn_len+"s %s") % (pn.upper()+":", opts_data['desc'].strip())
print (" %-"+pn_len+"s %s %s")%("USAGE:", pn, opts_data['usage'].strip())
sep = "\n "
print " OPTIONS:"+sep+"%s" % sep.join(help_data['options'].strip().split("\n"))
if "notes" in help_data:
print " %s" % "\n ".join(help_data['notes'][1:-1].split("\n"))
print " OPTIONS:"+sep+"%s" % sep.join(opts_data['options'].strip().split("\n"))
if "notes" in opts_data:
print " %s" % "\n ".join(opts_data['notes'][1:-1].split("\n"))
def process_opts(argv,help_data,short_opts,long_opts):
def process_opts(argv,opts_data,short_opts,long_opts):
import os
opts_data['prog_name'] = os.path.split(sys.argv[0])[1]
long_opts = [i.replace("_","-") for i in long_opts]
try: cl_opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
@ -48,7 +50,7 @@ def process_opts(argv,help_data,short_opts,long_opts):
else: short_opts_l += i
for opt, arg in cl_opts:
if opt in ("-h","--help"): print_help(help_data); sys.exit()
if opt in ("-h","--help"): print_help(opts_data); sys.exit()
elif opt[:2] == "--" and opt[2:] in long_opts:
opts[opt[2:].replace("-","_")] = True
elif opt[:2] == "--" and opt[2:]+"=" in long_opts:
@ -63,9 +65,9 @@ def process_opts(argv,help_data,short_opts,long_opts):
return opts,args
def parse_opts(argv,help_data):
def parse_opts(argv,opts_data):
lines = help_data['options'].strip().split("\n")
lines = opts_data['options'].strip().split("\n")
import re
pat = r"^-([a-zA-Z0-9]), --([a-zA-Z0-9-]{1,64})(=| )(.+)"
rep = r"-{0}, --{1}{w}{3}"
@ -75,10 +77,10 @@ def parse_opts(argv,help_data):
if d[2] == " ": d[2] = ""
short_opts = "".join([d[0]+d[2].replace("=",":") for d in opt_data])
long_opts = [d[1].replace("-","_")+d[2] for d in opt_data]
help_data['options'] = "\n".join(
opts_data['options'] = "\n".join(
[rep.format(w=" ", *m.groups())
if m else k for m,k in [(re.match(pat,l),l) for l in lines]]
)
opts,args = process_opts(argv,help_data,short_opts,long_opts)
opts,args = process_opts(argv,opts_data,short_opts,long_opts)
return opts,args,short_opts,long_opts

BIN
mmgen/share/Opts.pyc Normal file

Binary file not shown.

BIN
mmgen/share/__init__.pyc Normal file

Binary file not shown.

View file

@ -22,6 +22,7 @@ term.py: Terminal-handling routines for the MMGen suite
import sys, os, struct
import mmgen.config as g
import opt
from mmgen.util import msg, msg_r
def _kb_hold_protect_unix():

View file

@ -23,7 +23,7 @@ addr.py: Shared routines for the test suites
import sys,os
from binascii import hexlify
from mmgen.util import msg,write_to_file
import mmgen.config as g
import mmgen.opt as opt
_red,_grn,_yel,_cya,_reset = (
["\033[%sm" % c for c in "31;1","32;1","33;1","36;1","0"]
@ -58,7 +58,7 @@ def get_tmpfile_fn(cfg,fn):
return os.path.join(cfg['tmpdir'],fn)
def write_to_tmpfile(cfg,fn,data):
write_to_file(os.path.join(cfg['tmpdir'],fn),data,{},silent=True)
write_to_file(os.path.join(cfg['tmpdir'],fn),data,silent=True)
def read_from_tmpfile(cfg,fn):
from mmgen.util import get_data_from_file
@ -69,7 +69,7 @@ def read_from_file(fn):
return get_data_from_file(fn,silent=True)
def ok():
if g.verbose or g.exact_output:
if opt.verbose or opt.exact_output:
sys.stderr.write(green("OK\n"))
else: msg(" OK")

View file

@ -25,11 +25,11 @@ import mmgen.bitcoin as bitcoin
import binascii as ba
import mmgen.config as g
import mmgen.opt as opt
from mmgen.crypto import *
from mmgen.util import *
from mmgen.tx import *
opts = {}
from collections import OrderedDict
cmd_data = OrderedDict([
("help", []),
@ -230,7 +230,7 @@ def print_convert_results(indata,enc,dec,dtype):
error = False if are_equal(indata,dec,dtype) else True
if error or g.verbose:
if error or opt.verbose:
Msg("Input: %s" % repr(indata))
Msg("Encoded data: %s" % repr(enc))
Msg("Recoded data: %s" % repr(dec))
@ -470,13 +470,13 @@ def hex2wif(hexpriv,compressed=False):
def encrypt(infile,outfile="",hash_preset=""):
data = get_data_from_file(infile,"data for encryption")
enc_d = mmgen_encrypt(data,"user data",hash_preset,opts)
enc_d = mmgen_encrypt(data,"user data",hash_preset)
if outfile == '-':
write_to_stdout(enc_d,"encrypted data",confirm=True)
else:
if not outfile:
outfile = os.path.basename(infile) + "." + g.mmenc_ext
write_to_file(outfile, enc_d, opts,"encrypted data",True,True)
write_to_file(outfile,enc_d,"encrypted data",True,True)
def decrypt(infile,outfile="",hash_preset=""):
@ -494,7 +494,7 @@ def decrypt(infile,outfile="",hash_preset=""):
outfile = outfile[:-len(g.mmenc_ext)-1]
else:
outfile = outfile + ".dec"
write_to_file(outfile, dec_d, opts,"decrypted data",True,True)
write_to_file(outfile, dec_d, "decrypted data",True,True)
def find_incog_data(filename,iv_id,keep_searching=False):
@ -553,7 +553,7 @@ def rand2file(outfile, nbytes, threads=4, silent=False):
from threading import Thread
bsize = 2**20
roll = bsize * 4
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
f = open(outfile,"w")
from Crypto.Cipher import AES

View file

@ -26,6 +26,7 @@ from decimal import Decimal
from collections import OrderedDict
import mmgen.config as g
import mmgen.opt as opt
from mmgen.util import *
from mmgen.term import do_pager
@ -45,7 +46,7 @@ def normalize_btc_amt(amt):
msg("%s: Invalid amount" % amt)
return False
if g.debug:
if opt.debug:
print "Decimal(amt): %s\nAs tuple: %s" % (amt,repr(ret.as_tuple()))
if ret.as_tuple()[-1] < -8:
@ -260,7 +261,7 @@ def wiftoaddr_keyconv(wif):
return wiftoaddr(wif)
def get_wif2addr_f():
if g.no_keyconv: return wiftoaddr
if opt.no_keyconv: return wiftoaddr
from mmgen.addr import test_for_keyconv
return wiftoaddr_keyconv if test_for_keyconv() else wiftoaddr

View file

@ -26,27 +26,37 @@ from binascii import hexlify,unhexlify
import mmgen.config as g
def msg(s): sys.stderr.write(s + "\n")
_red,_grn,_yel,_cya,_reset = (
["\033[%sm" % c for c in "31;1","32;1","33;1","36;1","0"]
)
def red(s): return _red+s+_reset
def green(s): return _grn+s+_reset
def yellow(s): return _yel+s+_reset
def cyan(s): return _cya+s+_reset
def msgred(s): sys.stderr.write(red(s+"\n"))
def msg(s): sys.stderr.write(s+"\n")
def msg_r(s): sys.stderr.write(s)
def qmsg(s,alt=False):
if g.quiet:
if opt.quiet:
if alt != False: sys.stderr.write(alt + "\n")
else: sys.stderr.write(s + "\n")
def qmsg_r(s,alt=False):
if g.quiet:
if opt.quiet:
if alt != False: sys.stderr.write(alt)
else: sys.stderr.write(s)
def vmsg(s):
if g.verbose: sys.stderr.write(s + "\n")
if opt.verbose: sys.stderr.write(s + "\n")
def vmsg_r(s):
if g.verbose: sys.stderr.write(s)
if opt.verbose: sys.stderr.write(s)
def Msg(s): sys.stdout.write(s + "\n")
def Msg_r(s): sys.stdout.write(s)
def Vmsg(s):
if g.verbose: sys.stdout.write(s + "\n")
if opt.verbose: sys.stdout.write(s + "\n")
def Vmsg_r(s):
if g.verbose: sys.stdout.write(s)
if opt.verbose: sys.stdout.write(s)
def msgrepr(*args):
@ -122,8 +132,10 @@ def is_utf8(s):
def match_ext(addr,ext):
return addr.split(".")[-1] == ext
def get_from_brain_opt_params(opts):
l,p = opts['from_brain'].split(",")
import opt as opt
def get_from_brain_opt_params():
l,p = opt.from_brain.split(",")
return(int(l),p)
def pretty_hexdump(data,gw=2,cols=8,line_nums=False):
@ -165,7 +177,7 @@ def compare_checksums(chksum1, desc1, chksum2, desc2):
vmsg("OK (%s)" % chksum1.upper())
return True
else:
if g.debug:
if opt.debug:
print \
"ERROR!\nComputed checksum %s (%s) doesn't match checksum %s (%s)" \
% (desc1,chksum1,desc2,chksum2)
@ -266,18 +278,18 @@ def parse_addr_idxs(arg,sep=","):
return sorted(set(ret))
def get_new_passphrase(what, opts, passchg=False):
def get_new_passphrase(what, passchg=False):
w = "{}passphrase for {}".format("new " if passchg else "", what)
if 'passwd_file' in opts:
pw = " ".join(_get_words_from_file(opts['passwd_file'],w))
elif 'echo_passphrase' in opts:
pw = " ".join(_get_words_from_user("Enter {}: ".format(w), opts))
if opt.passwd_file:
pw = " ".join(_get_words_from_file(opt.passwd_file,w))
elif opt.echo_passphrase:
pw = " ".join(_get_words_from_user("Enter {}: ".format(w)))
else:
for i in range(g.passwd_max_tries):
pw = " ".join(_get_words_from_user("Enter {}: ".format(w),opts))
pw2 = " ".join(_get_words_from_user("Repeat passphrase: ",opts))
if g.debug: print "Passphrases: [%s] [%s]" % (pw,pw2)
pw = " ".join(_get_words_from_user("Enter {}: ".format(w)))
pw2 = " ".join(_get_words_from_user("Repeat passphrase: "))
if opt.debug: print "Passphrases: [%s] [%s]" % (pw,pw2)
if pw == pw2:
vmsg("Passphrases match"); break
else: msg("Passphrases do not match. Try again.")
@ -324,9 +336,9 @@ def write_to_stdout(data, what, confirm=True):
sys.stdout.write(data)
def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=False,exit_on_error=True,silent=False):
def write_to_file(outfile,data,what="data",confirm_overwrite=False,verbose=False,exit_on_error=True,silent=False):
if 'outdir' in opts: outfile = make_full_path(opts['outdir'],outfile)
if opt.outdir: outfile = make_full_path(opt.outdir,outfile)
from os import stat
try: stat(outfile)
@ -355,18 +367,18 @@ def write_to_file(outfile,data,opts,what="data",confirm_overwrite=False,verbose=
return True
def write_to_file_or_stdout(outfile, data, opts, what="data"):
def write_to_file_or_stdout(outfile, data, what="data"):
if 'stdout' in opts or not sys.stdout.isatty():
if opt.stdout or not sys.stdout.isatty():
write_to_stdout(data, what, confirm=True)
else:
write_to_file(outfile,data,opts,what,not g.quiet,True)
write_to_file(outfile,data,what,not opt.quiet,True)
from mmgen.bitcoin import b58decode_pad,b58encode_pad
def display_control_data(label,metadata,hash_preset,salt,enc_seed):
msg("WALLET DATA")
print "WALLET DATA"
fs = " {:18} {}"
pw_empty = "yes" if metadata[3] == "E" else "no"
for i in (
@ -379,7 +391,7 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed):
" ".join([str(i) for i in get_hash_params(hash_preset)]))),
("Passphrase empty?", pw_empty.capitalize()),
("Timestamp:", "%s UTC" % metadata[4]),
): msg(fs.format(*i))
): print fs.format(*i)
fs = " {:6} {}"
for i in (
@ -389,16 +401,16 @@ def display_control_data(label,metadata,hash_preset,salt,enc_seed):
("Encrypted seed:", ""),
(" b58:", b58encode_pad(enc_seed)),
(" hex:", hexlify(enc_seed))
): msg(fs.format(*i))
): print fs.format(*i)
def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed):
seed_id = make_chksum_8(seed)
seed_len = str(len(seed)*8)
pw_status = "NE" if len(passwd) else "E"
hash_preset = opts['hash_preset']
label = opts['label'] if 'label' in opts else "No Label"
hash_preset = opt.hash_preset
label = opt.label if opt.label else "No Label"
metadata = seed_id.lower(),key_id.lower(),seed_len,\
pw_status,make_timestamp()
sf = b58encode_pad(salt)
@ -417,9 +429,9 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
seed_id,key_id,seed_len,hash_preset,g.wallet_ext)
d = "\n".join((chk,)+lines)+"\n"
write_to_file(outfile,d,opts,"wallet",not g.quiet,True)
write_to_file(outfile,d,"wallet",not opt.quiet,True)
if g.debug:
if opt.debug:
display_control_data(label,metadata,hash_preset,salt,enc_seed)
@ -467,7 +479,7 @@ def _check_chksum_6(chk,val,desc,infile):
msg("%s checksum incorrect in file '%s'!" % (desc,infile))
msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
sys.exit(2)
elif g.debug:
elif opt.debug:
print "%s checksum passed: %s" % (desc.capitalize(),chk)
@ -475,7 +487,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 g.quiet:
if not silent and not opt.quiet:
msg("Getting {} wallet data from file '{}'".format(g.proj_name,infile))
f = open_file_or_exit(infile, 'r')
@ -515,10 +527,10 @@ def get_data_from_wallet(infile,silent=False):
return label,metadata,hash_preset,res['salt'],res['enc_seed']
def _get_words_from_user(prompt, opts):
def _get_words_from_user(prompt):
# split() also strips
words = my_raw_input(prompt, echo='echo_passphrase' in opts).split()
if g.debug: print "Sanitized input: [%s]" % " ".join(words)
words = my_raw_input(prompt, echo=opt.echo_passphrase).split()
if opt.debug: print "Sanitized input: [%s]" % " ".join(words)
return words
@ -528,15 +540,15 @@ def _get_words_from_file(infile,what):
# split() also strips
words = f.read().split()
f.close()
if g.debug: print "Sanitized input: [%s]" % " ".join(words)
if opt.debug: print "Sanitized input: [%s]" % " ".join(words)
return words
def get_words(infile,what,prompt,opts):
def get_words(infile,what,prompt):
if infile:
return _get_words_from_file(infile,what)
else:
return _get_words_from_user(prompt,opts)
return _get_words_from_user(prompt)
def remove_comments(lines):
import re
@ -594,31 +606,31 @@ def get_seed_from_seed_data(words):
passwd_file_used = False
def mark_passwd_file_as_used(opts):
def mark_passwd_file_as_used():
global passwd_file_used
if passwd_file_used:
msg_r("WARNING: Reusing passphrase from file '%s'." % opts['passwd_file'])
msg_r("WARNING: Reusing passphrase from file '%s'." % opt.passwd_file)
msg(" This may not be what you want!")
passwd_file_used = True
def get_mmgen_passphrase(prompt_info,opts,passchg=False):
def get_mmgen_passphrase(prompt_info,passchg=False):
prompt = "Enter {}passphrase for {}: ".format(
"old " if passchg else "",prompt_info)
if 'passwd_file' in opts:
mark_passwd_file_as_used(opts)
return " ".join(_get_words_from_file(opts['passwd_file'],"passphrase"))
if opt.passwd_file:
mark_passwd_file_as_used()
return " ".join(_get_words_from_file(opt.passwd_file,"passphrase"))
else:
return " ".join(_get_words_from_user(prompt,opts))
return " ".join(_get_words_from_user(prompt))
def get_bitcoind_passphrase(prompt,opts):
if 'passwd_file' in opts:
mark_passwd_file_as_used(opts)
return get_data_from_file(opts['passwd_file'],
def get_bitcoind_passphrase(prompt):
if opt.passwd_file:
mark_passwd_file_as_used()
return get_data_from_file(opt.passwd_file,
"passphrase").strip("\r\n")
else:
return my_raw_input(prompt, echo='echo_passphrase' in opts)
return my_raw_input(prompt, echo=opt.echo_passphrase)
def check_data_fits_file_at_offset(fname,offset,dlen,action):

View file

@ -1,12 +1,33 @@
#!/usr/bin/env python
#
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
# Copyright (C)2013-2015 Philemon <mmgen-py@yandex.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from distutils.core import setup
setup(
name = 'mmgen',
decription = 'A complete Bitcoin cold-storage solution for the command line',
version = '0.7.9',
author = 'Philemon',
author_email = 'mmgen-py@yandex.com',
url = 'https://github.com/mmgen/mmgen',
license = 'GNU GPL v3',
platforms = 'Linux, MS Windows',
keywords = 'Bitcoin, wallet, cold storage, offline storage, open-source, command-line, Python, Bitcoin Core, bitcoind',
py_modules = [
'mmgen.__init__',
'mmgen.addr',
@ -17,7 +38,8 @@ setup(
'mmgen.mn_electrum',
'mmgen.mnemonic',
'mmgen.mn_tirosh',
'mmgen.Opts',
'mmgen.opts',
'mmgen.opt',
'mmgen.term',
'mmgen.test',
'mmgen.tool',
@ -36,8 +58,8 @@ setup(
'mmgen.main_walletchk',
'mmgen.main_walletgen',
'mmgen.opt.__init__',
'mmgen.opt.Opts',
'mmgen.share.__init__',
'mmgen.share.Opts',
'mmgen.rpc.__init__',
'mmgen.rpc.config',

View file

@ -9,6 +9,7 @@ os.chdir(os.path.join(pn,os.pardir))
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.test import *
@ -202,15 +203,14 @@ meta_cmds = OrderedDict([
['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref"))],
])
from mmgen.Opts import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Test suite for the MMGen suite",
'usage':"[options] [command or metacommand]",
'options': """
-h, --help Print this help message
-b, --buf-keypress Use buffered keypresses as with real human input
-d, --debug Produce debugging output
-D, --direct-exec Bypass pexpect and execute a command directly (for debugging only)
-e, --exact-output Show the exact output of the MMGen script(s) being run
-l, --list-cmds List and describe the tests and commands in the test suite
-p, --pause Pause between tests, resuming on keypress
@ -224,47 +224,43 @@ If no command is given, the whole suite of tests is run.
"""
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data)
if 'system' in opts: sys.path.pop(0)
if opt.system: sys.path.pop(0)
env = os.environ
if 'buf_keypress' in opts:
if opt.buf_keypress:
send_delay = 0.3
else:
send_delay = 0
env["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
for k in 'debug','verbose','exact_output','pause','quiet':
g.__dict__[k] = True if k in opts else False
if opt.debug: opt.verbose = True
if g.debug: g.verbose = True
if g.exact_output:
if opt.exact_output:
def msg(s): pass
vmsg = vmsg_r = msg_r = msg
else:
def msg(s): sys.stderr.write(s+"\n")
def vmsg(s):
if g.verbose: sys.stderr.write(s+"\n")
if opt.verbose: sys.stderr.write(s+"\n")
def msg_r(s): sys.stderr.write(s)
def vmsg_r(s):
if g.verbose: sys.stderr.write(s)
if opt.verbose: sys.stderr.write(s)
stderr_save = sys.stderr
def silence():
if not (g.verbose or g.exact_output):
if not (opt.verbose or opt.exact_output):
sys.stderr = open("/dev/null","a")
def end_silence():
if not (g.verbose or g.exact_output):
if not (opt.verbose or opt.exact_output):
sys.stderr = stderr_save
def errmsg(s): stderr_save.write(s+"\n")
def errmsg_r(s): stderr_save.write(s)
if "list_cmds" in opts:
if opt.list_cmds:
fs = " {:<{w}} - {}"
Msg("Available commands:")
w = max([len(i) for i in cmd_data])
@ -281,15 +277,14 @@ if "list_cmds" in opts:
sys.exit()
import pexpect,time,re
import mmgen.config as g
from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file
def my_send(p,t,delay=send_delay,s=False):
if delay: time.sleep(delay)
ret = p.send(t) # returns num bytes written
if delay: time.sleep(delay)
if g.verbose:
ls = "" if g.debug or not s else " "
if opt.verbose:
ls = "" if opt.debug or not s else " "
es = "" if s else " "
msg("%sSEND %s%s" % (ls,es,yellow("'%s'"%t.replace('\n',r'\n'))))
return ret
@ -297,7 +292,7 @@ def my_send(p,t,delay=send_delay,s=False):
def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
quo = "'" if type(s) == str else ""
if g.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo))
if opt.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo))
else: msg_r("+")
try:
@ -309,7 +304,7 @@ def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
errmsg(red("\nERROR. Expect %s%s%s timed out. Exiting" % (quo,s,quo)))
sys.exit(1)
if g.debug or (g.verbose and type(s) != str): msg_r(" ==> %s " % ret)
if opt.debug or (opt.verbose and type(s) != str): msg_r(" ==> %s " % ret)
if ret == -1:
errmsg("Error. Expect returned %s" % ret)
@ -329,7 +324,7 @@ def get_file_with_ext(ext,mydir,delete=True):
if len(flist) > 1:
if delete:
if not g.quiet:
if not opt.quiet:
msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
for f in flist: os.unlink(f)
return False
@ -341,7 +336,7 @@ def get_addrfile_checksum(display=False):
silence()
from mmgen.addr import AddrInfo
chk = AddrInfo(addrfile).checksum
if g.verbose and display: msg("Checksum: %s" % cyan(chk))
if opt.verbose and display: msg("Checksum: %s" % cyan(chk))
end_silence()
return chk
@ -354,21 +349,24 @@ def verify_checksum_or_exit(checksum,chk):
class MMGenExpect(object):
def __init__(self,name,mmgen_cmd,cmd_args=[],env=env):
if not 'system' in opts:
def __init__(self,name,mmgen_cmd,cmd_args=[]):
if not opt.system:
mmgen_cmd = os.path.join(os.curdir,mmgen_cmd)
desc = cmd_data[name][1]
if g.verbose or g.exact_output:
if opt.verbose or opt.exact_output:
sys.stderr.write(
green("Testing %s\nExecuting " % desc) +
cyan("'%s %s'\n" % (mmgen_cmd," ".join(cmd_args)))
)
else:
msg_r("Testing %s " % (desc+":"))
# msgrepr(mmgen_cmd,cmd_args); msg("")
if env: self.p = pexpect.spawn(mmgen_cmd,cmd_args,env=env)
else: self.p = pexpect.spawn(mmgen_cmd,cmd_args)
if g.exact_output: self.p.logfile = sys.stdout
if opt.direct_exec:
os.system(" ".join([mmgen_cmd] + cmd_args))
sys.exit()
else:
self.p = pexpect.spawn(mmgen_cmd,cmd_args)
if opt.exact_output: self.p.logfile = sys.stdout
def license(self):
p = "'w' for conditions and warranty info, or 'c' to continue: "
@ -381,7 +379,7 @@ class MMGenExpect(object):
vmsg_r("SEND ")
while self.p.expect('left: ',0.1) == 0:
ch = rand_chars.pop(0)
msg_r(yellow(ch)+" " if g.verbose else "+")
msg_r(yellow(ch)+" " if opt.verbose else "+")
self.p.send(ch)
except:
vmsg("EOT")
@ -476,12 +474,12 @@ def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input='')
btcaddr = privnum2addr(privnum,compressed=True)
of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
write_to_file(of, hextowif("{:064x}".format(privnum),
compressed=True)+"\n",{},"compressed bitcoin key")
compressed=True)+"\n","compressed bitcoin key")
add_fake_unspent_entry(out,btcaddr,"Non-MMGen address")
# msg("\n".join([repr(o) for o in out])); sys.exit()
write_to_file(unspent_data_file,repr(out),{},"Unspent outputs",verbose=True)
write_to_file(unspent_data_file,repr(out),"Unspent outputs",verbose=True)
def add_comments_to_addr_file(addrfile,tfile):
@ -503,18 +501,18 @@ def make_brainwallet_file(fn):
return "".join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)])
rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)]
d = "".join(rand_pairs).rstrip() + "\n"
if g.verbose: msg_r("Brainwallet password:\n%s" % cyan(d))
write_to_file(fn,d,{},"brainwallet password")
if opt.verbose: msg_r("Brainwallet password:\n%s" % cyan(d))
write_to_file(fn,d,"brainwallet password")
def do_between():
if g.pause:
if opt.pause:
from mmgen.util import keypress_confirm
if keypress_confirm(green("Continue?"),default_yes=True):
if g.verbose or g.exact_output: sys.stderr.write("\n")
if opt.verbose or opt.exact_output: sys.stderr.write("\n")
else:
errmsg("Exiting at user request")
sys.exit()
elif g.verbose or g.exact_output:
elif opt.verbose or opt.exact_output:
sys.stderr.write("\n")
@ -569,7 +567,7 @@ def refcheck(what,chk,refchk):
if chk == refchk:
ok()
else:
if not g.verbose: errmsg("")
if not opt.verbose: errmsg("")
errmsg(red("""
Fatal error - %s '%s' does not match reference value '%s'. Aborting test
""".strip() % (what,chk,refchk)))
@ -586,7 +584,7 @@ def check_deps(ts,name,cmds):
msg("'%s': unrecognized command" % cmd)
sys.exit(1)
if not g.quiet:
if not opt.quiet:
msg("Checking dependencies for '%s'" % (cmd))
check_needs_rerun(ts,cmd,build=False)
@ -603,8 +601,8 @@ def clean(dirs=[]):
ts = MMGenTestSuite()
dirlist = ts.list_tmp_dirs()
if not dirs: dirs = dirlist.keys()
for d in dirs:
if d in sorted(dirlist):
for d in sorted(dirs):
if d in dirlist:
cleandir(dirlist[d])
else:
msg("%s: invalid directory number" % d)
@ -741,7 +739,7 @@ class MMGenTestSuite(object):
self.txcreate_common(name,sources=['1'])
def txcreate_common(self,name,sources=['1'],non_mmgen_input=''):
if g.verbose or g.exact_output:
if opt.verbose or opt.exact_output:
sys.stderr.write(green("Generating fake transaction info\n"))
silence()
from mmgen.addr import AddrInfo,AddrInfoList
@ -784,11 +782,11 @@ class MMGenTestSuite(object):
for num in tx_data: cmd_args += [tx_data[num]['addrfile']]
env["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file
os.environ["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file
end_silence()
if g.verbose or g.exact_output: sys.stderr.write("\n")
if opt.verbose or opt.exact_output: sys.stderr.write("\n")
t = MMGenExpect(name,"mmgen-txcreate",cmd_args,env)
t = MMGenExpect(name,"mmgen-txcreate",cmd_args)
t.license()
for num in tx_data.keys():
t.expect_getend("Getting address data from file ")
@ -871,7 +869,7 @@ class MMGenTestSuite(object):
def export_incog_hidden(self,name,walletfile):
rf,rd = os.path.join(cfg['tmpdir'],hincog_fn),os.urandom(hincog_bytes)
vmsg(green("Writing %s bytes of data to file '%s'" % (hincog_bytes,rf)))
write_to_file(rf,rd,{},verbose=g.verbose)
write_to_file(rf,rd,verbose=opt.verbose)
t = self.export_incog(name,walletfile,args=["-G","%s,%s"%(rf,hincog_offset)])
t.written_to_file("Data",query="")
ok()
@ -1033,7 +1031,7 @@ class MMGenTestSuite(object):
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)
write_to_file(infn,cfg['tool_enc_reftext'],silent=True)
self.tool_encrypt(name,infn)
# Two deps produced by one prog is broken - TODO
@ -1051,7 +1049,7 @@ class MMGenTestSuite(object):
self.tool_decrypt(name,f1,f2)
# main()
if g.pause:
if opt.pause:
import termios,atexit
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)

View file

@ -8,7 +8,7 @@ pn = os.path.dirname(sys.argv[0])
os.chdir(os.path.join(pn,os.pardir))
sys.path.__setitem__(0,os.path.abspath(os.curdir))
import mmgen.config as g
import mmgen.opt as opt
from mmgen.util import msg,msg_r,vmsg,vmsg_r,Msg,msgrepr, msgrepr_exit
from collections import OrderedDict
@ -74,9 +74,7 @@ cfg = {
'tmpdir_num': 10,
}
from mmgen.Opts import *
help_data = {
'prog_name': g.prog_name,
opts_data = {
'desc': "Test suite for the 'mmgen-tool' utility",
'usage':"[options] [command]",
'options': """
@ -92,18 +90,15 @@ If no command is given, the whole suite of tests is run.
"""
}
opts,cmd_args = parse_opts(sys.argv,help_data)
cmd_args = opt.opts.init(opts_data,add_opts=["exact_output"])
if 'system' in opts: sys.path.pop(0)
if opt.system: sys.path.pop(0)
env = os.environ
for k in 'debug','verbose','quiet','exact_output':
g.__dict__[k] = True if k in opts else False
if opt.debug: opt.verbose = True
if g.debug: g.verbose = True
if "list_cmds" in opts:
if opt.list_cmds:
fs = " {:<{w}} - {}"
Msg("Available commands:")
w = max([len(i) for i in cmd_data])
@ -114,7 +109,6 @@ if "list_cmds" in opts:
sys.exit()
import binascii
import mmgen.config as g
from mmgen.test import *
from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file
from mmgen.tx import is_wif,is_btc_addr,is_b58_str
@ -162,14 +156,14 @@ class MMGenToolTestSuite(object):
def run_cmd(self,name,tool_args,kwargs="",extra_msg="",silent=False):
mmgen_tool = "mmgen-tool"
if not 'system' in opts:
if not opt.system:
mmgen_tool = os.path.join(os.curdir,mmgen_tool)
sys_cmd = [mmgen_tool, "-d",cfg['tmpdir'], name] + tool_args + kwargs.split()
if extra_msg: extra_msg = "(%s)" % extra_msg
full_name = " ".join([name]+kwargs.split()+extra_msg.split())
if not silent:
if g.verbose:
if opt.verbose:
sys.stderr.write(green("Testing %s\nExecuting " % full_name))
sys.stderr.write("%s\n" % cyan(repr(sys_cmd)))
else: