Longer checksum for addrfile, bugfixes, code cleanups

This commit is contained in:
philemon 2014-07-31 00:11:28 +04:00
commit 791fc1910f
14 changed files with 170 additions and 245 deletions

View file

@ -29,17 +29,19 @@ from mmgen.Opts import *
from mmgen.license import *
from mmgen.util import *
from mmgen.addr import *
from mmgen.tx import make_addr_data_chksum
gen_what = "addresses" if sys.argv[0].split("-")[-1] == "addrgen" else "keys"
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'prog_name': g.prog_name,
'desc': """Generate a list or range of {} from an {g.proj_name} wallet,
mnemonic, seed or password""".format(gen_what,g=g),
'usage':"[opts] [infile] <address list>",
'options': """
-h, --help Print this help message{}
-d, --outdir= d Specify an alternate directory 'd' for output
-c, --save-checksum Save address list checksum to file
-e, --echo-passphrase Echo passphrase or mnemonic to screen upon entry{}
-H, --show-hash-presets Show information on available hash presets
-K, --no-keyconv Use internal libraries for address generation
@ -66,10 +68,10 @@ help_data = {
""".format(
*(
(
"\n-A, --no-addresses Print only secret keys, no addresses",
"\n-f, --flat-list Produce a flat list of keys suitable for use with" +
"\n 'mmgen-txsign'",
"\n-x, --b16 Print secret keys in hexadecimal too"
"\n-A, --no-addresses Print only secret keys, no addresses",
"\n-f, --flat-list Produce a flat list of keys suitable for use with" +
"\n '{}-txsign'".format(g.proj_name.lower()),
"\n-x, --b16 Print secret keys in hexadecimal too"
)
if gen_what == "keys" else ("","","")),
seed_lens=", ".join([str(i) for i in g.seed_lens]),
@ -148,29 +150,36 @@ if gen_what == "addresses":
else:
if not 'no_addresses' in opts: opts['print_secret'] = True
seed = get_seed_retry(infile,opts)
seed_id = make_chksum_8(seed)
seed = get_seed_retry(infile,opts)
seed_id = make_chksum_8(seed)
addr_data = generate_addrs(seed, addr_idxs, opts)
addr_data_chksum = make_chksum_8(
" ".join(["{} {}".format(a['num'],a['addr']) for a in addr_data]),
sep=True
)
addr_data_str = format_addr_data(
addr_data = generate_addrs(seed, addr_idxs, opts)
addr_data_chksum = make_addr_data_chksum([(a['num'],a['addr'])
for a in addr_data]) if not 'no_addresses' in opts else ""
addr_data_str = format_addr_data(
addr_data, addr_data_chksum, seed_id, addr_idxs, opts)
outfile_base = "{}[{}]".format(seed_id, fmt_addr_idxs(addr_idxs))
# Output data:
if 'stdout' in opts:
if gen_what == "keys" and not g.quiet:
confirm = True
else: confirm = False
confirm = True if (gen_what == "keys" and not g.quiet) else False
write_to_stdout(addr_data_str,gen_what,confirm)
elif not sys.stdout.isatty():
write_to_stdout(addr_data_str,gen_what,confirm=False)
else:
write_addr_data_to_file(seed, addr_data_str, addr_idxs, opts)
confirm = False if g.quiet else True
outfile = outfile_base + "." + (
g.addrfile_ext if 'print_addresses_only' in opts else (
g.keyfile_ext if 'no_addresses' in opts else (
g.keylist_ext if 'flat_list' in opts else "akeys"))
)
write_to_file(outfile,addr_data_str,opts,gen_what,confirm,True)
msg("""
Checksum for address data {}[{}]: {}
Remember this checksum or save it to a secure location
""".format(seed_id, fmt_addr_idxs(addr_idxs), addr_data_chksum).strip())
if not 'no_addresses' in opts:
msg("Checksum for address data {}: {}".format(outfile_base,addr_data_chksum))
if 'save_checksum' in opts:
a = "address data checksum"
write_to_file(outfile_base+".chk",addr_data_chksum,opts,a,confirm,True)
else:
qmsg("Save this information to a secure location")

View file

@ -27,7 +27,7 @@ from mmgen.util import *
from mmgen.tx import connect_to_bitcoind,parse_addrs_file
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'prog_name': g.prog_name,
'desc': """Import addresses (both {pnm} and non-{pnm}) into a bitcoind
watching wallet""".format(pnm=g.proj_name),
'usage':"[opts] [mmgen address file]",

View file

@ -43,9 +43,6 @@ mmgen-pywallet: Dump contents of a bitcoind wallet to file
# Alex Martelli (http://www.aleax.it)
# Ported from C code written by Laurent Haan (http://www.progressive-coding.com)
from mmgen.Opts import *
from mmgen.util import msg
import mmgen.config as g
from bsddb.db import *
import sys, time
import json
@ -61,16 +58,18 @@ import hashlib
import random
import math
import mmgen.config as g
from mmgen.Opts import *
from mmgen.util import msg
max_version = 60000
addrtype = 0
json_db = {}
private_keys = []
password = None
prog_name = sys.argv[0].split("/")[-1]
help_data = {
'prog_name': prog_name,
'prog_name': g.prog_name,
'desc': "Dump contents of a bitcoind wallet to file",
'usage': "[opts] <bitcoind wallet file>",
'options': """

View file

@ -22,17 +22,17 @@ mmgen-tool: Perform various Bitcoin-related operations - part of the MMGen suite
import sys, os
from hashlib import sha256
from mmgen.Opts import *
import mmgen.config as g
from mmgen.util import pretty_hexdump
import mmgen.tool as tool
prog_name = sys.argv[0].split("/")[-1]
from mmgen.Opts import *
from mmgen.util import pretty_hexdump
help_data = {
'prog_name': prog_name,
'prog_name': g.prog_name,
'desc': "Perform various BTC-related operations",
'usage': "[opts] <command> <args>",
'options': """
-d, --outdir= d Specify an alternate directory 'd' for output
-h, --help Print this help message
-q, --quiet Produce quieter output
-r, --usr-randchars=n Get 'n' characters of additional randomness from
@ -44,7 +44,7 @@ help_data = {
COMMANDS:{}
Type '{} <command> --help for usage information on a particular
command
""".format(tool.command_help,prog_name)
""".format(tool.command_help,g.prog_name)
}
opts,cmd_args = parse_opts(sys.argv,help_data)
@ -63,10 +63,10 @@ if command not in tool.commands.keys():
sys.exit(1)
if cmd_args and cmd_args[0] == '--help':
tool.tool_usage(prog_name, command)
tool.tool_usage(g.prog_name, command)
sys.exit(0)
args = tool.process_args(prog_name, command, cmd_args)
args = tool.process_args(g.prog_name, command, cmd_args)
tool.opts = opts

View file

@ -20,19 +20,16 @@ mmgen-txcreate: Create a BTC transaction, sending to specified addresses
"""
import sys
#from hashlib import sha256
from mmgen.Opts import *
from mmgen.license import *
import mmgen.config as g
from mmgen.tx import *
from mmgen.util import msg, msg_r, user_confirm
from decimal import Decimal
prog_name = sys.argv[0].split("/")[-1]
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
from mmgen.tx import *
from mmgen.util import msg, msg_r, user_confirm
help_data = {
'prog_name': prog_name,
'prog_name': g.prog_name,
'desc': "Create a BTC transaction with outputs to specified addresses",
'usage': "[opts] <addr,amt> ... [change addr] [addr file] ...",
'options': """
@ -69,6 +66,7 @@ if g.debug: show_opts_and_cmd_args(opts,cmd_args)
c = connect_to_bitcoind()
if not 'info' in opts:
do_license_msg(immed=True)
tx_out,addr_data,b2m_map,acct_data,change_addr = {},[],{},[],""
@ -132,9 +130,9 @@ if not 'info' in opts:
if g.debug: show_opts_and_cmd_args(opts,cmd_args)
if not 'info' in opts: do_license_msg(immed=True)
#write_to_file("bogus_unspent.json", repr(us), opts); sys.exit()
#write_to_file("bogus_unspent.json", repr(us)); sys.exit()
#if False:
if g.bogus_wallet_data:
import mmgen.rpc
us = eval(get_data_from_file(g.bogus_wallet_data))
@ -143,7 +141,7 @@ else:
if not us: msg(txmsg['no_spendable_outputs']); sys.exit(2)
unspent = sort_and_view(us)
unspent = sort_and_view(us,opts)
total = trim_exponent(sum([i.amount for i in unspent]))
@ -209,6 +207,15 @@ if reply and reply in "YyVv":
prompt = "Save transaction?"
if user_confirm(prompt,default_yes=True):
write_tx_to_file(tx_hex,sel_unspent,send_amt or change,b2m_map,opts)
amt = send_amt or change
tx_id = make_chksum_6(unhexlify(tx_hex)).upper()
outfile = "tx_%s[%s].%s" % (tx_id,amt,g.rawtx_ext)
data = "{} {} {}\n{}\n{}\n{}\n".format(
tx_id, amt, make_timestamp(),
tx_hex,
repr([i.__dict__ for i in sel_unspent]),
repr(b2m_map)
)
write_to_file(outfile,data,opts,"transaction",False,True)
else:
msg("Transaction not saved")

View file

@ -21,17 +21,15 @@ mmgen-txsend: Broadcast a Bitcoin transaction to the network
import sys
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
import mmgen.config as g
from mmgen.tx import *
from mmgen.util import msg,check_infile,get_lines_from_file,confirm_or_exit
prog_name = sys.argv[0].split("/")[-1]
help_data = {
'prog_name': prog_name,
'desc': "Send a Bitcoin transaction signed by mmgen-txsign",
'prog_name': g.prog_name,
'desc': "Send a Bitcoin transaction signed by {}-txsign".format(g.proj_name.lower()),
'usage': "[opts] <signed transaction file>",
'options': """
-h, --help Print this help message
@ -84,4 +82,5 @@ except:
msg("Transaction sent: %s" % tx_id)
write_sent_tx_num_to_file(tx_id,metadata,opts)
of = "tx_{}[{}].out".format(*metadata[:2])
write_to_file(of, tx_id+"\n",opts,"transaction ID",True,True)

View file

@ -21,15 +21,15 @@ mmgen-txsign: Sign a Bitcoin transaction generated by mmgen-txcreate
import sys
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
import mmgen.config as g
from mmgen.tx import *
from mmgen.util import msg,qmsg
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'desc': "Sign Bitcoin transactions generated by mmgen-txcreate",
'prog_name': g.prog_name,
'desc': "Sign Bitcoin transactions generated by {}-txcreate".format(g.proj_name.lower()),
'usage': "[opts] <transaction file> .. [mmgen wallet/seed/words/brainwallet file] .. [addrfile] ..",
'options': """
-h, --help Print this help message
@ -63,7 +63,7 @@ help_data = {
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
mmgen-addrgen and mmgen-keygen utilities.
{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
@ -84,7 +84,7 @@ 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,pnm=g.proj_name)
""".format(g=g,pnm=g.proj_name,pnl=g.proj_name.lower())
}
opts,infiles = parse_opts(sys.argv,help_data)
@ -184,7 +184,14 @@ for tx_file in tx_files:
if sig_tx['complete']:
prompt = "OK\nSave signed transaction?"
if user_confirm(prompt,default_yes=True):
write_signed_tx_to_file(tx_hex,sig_tx['hex'],metadata,inputs_data,b2m_map,opts)
outfile = "tx_%s[%s].%s" % (metadata[0],metadata[1],g.sigtx_ext)
data = "{}\n{}\n{}\n{}\n".format(
" ".join(metadata[:2] + [make_timestamp()]),
sig_tx['hex'],
repr(inputs_data),
repr(b2m_map)
)
write_to_file(outfile,data,opts,"signed transaction",True,True)
else:
msg("failed\nSome keys were missing. Transaction could not be signed.")
sys.exit(3)

View file

@ -21,12 +21,12 @@ mmgen-walletchk: Check integrity of a mmgen deterministic wallet, display
"""
import sys
import mmgen.config as g
from mmgen.Opts import *
from mmgen.util import *
help_data = {
'prog_name': sys.argv[0].split("/")[-1],
'prog_name': g.prog_name,
'desc': """Check integrity of an {} deterministic wallet, display
its information, and export seed and mnemonic data.
""".format(g.proj_name),
@ -89,7 +89,7 @@ elif 'export_incog' in opts:
)
data = pretty_hexdump(incog_enc,2,8,line_nums=False) \
if "export_incog_hex" in opts else incog_enc
export_to_file(fn, data, "incognito wallet data", opts)
export_to_file(fn, data, opts, "incognito wallet data")
sys.exit()
@ -105,11 +105,11 @@ if 'export_mnemonic' in opts:
p = True if g.debug else False
mn = get_mnemonic_from_seed(seed, wl, g.default_wl, print_info=p)
fn = "%s.%s" % (make_chksum_8(seed).upper(), g.mn_ext)
export_to_file(fn, " ".join(mn)+"\n", "mnemonic data", opts)
export_to_file(fn, " ".join(mn)+"\n", opts, "mnemonic data")
elif 'export_seed' in opts:
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)
export_to_file(fn, "%s %s\n" % (chk,data), "seed data", opts)
export_to_file(fn, "%s %s\n" % (chk,data), opts, "seed data")

View file

@ -22,15 +22,14 @@ mmgen-walletgen: Generate a mmgen deterministic wallet
import sys, os
from hashlib import sha256
import mmgen.config as g
from mmgen.Opts import *
from mmgen.license import *
import mmgen.config as g
from mmgen.walletgen import *
from mmgen.util import *
prog_name = sys.argv[0].split("/")[-1]
help_data = {
'prog_name': prog_name,
'prog_name': g.prog_name,
'desc': "Generate an {} deterministic wallet".format(g.proj_name),
'usage': "[opts] [infile]",
'options': """
@ -61,7 +60,7 @@ help_data = {
'notes': """
By default (i.e. when invoked without any of the '--from-<what>' options),
{prog_name} generates a wallet based on a random seed.
{g.prog_name} generates a wallet based on a random seed.
Data for the --from-<what> options will be taken from <infile> if <infile>
is specified. Otherwise, the user will be prompted to enter the data.
@ -91,7 +90,7 @@ the '--seed-len' option.
For a brainwallet passphrase to always generate the same keys and
addresses, the same 'l' and 'p' parameters to '--from-brain' must be used
in all future invocations with that passphrase.
""".format(prog_name=prog_name)
""".format(g=g)
}
opts,cmd_args = parse_opts(sys.argv,help_data)

View file

@ -133,43 +133,27 @@ def format_addr_data(addr_data, addr_data_chksum, seed_id, addr_idxs, opts):
start = addr_data[0]['num']
end = addr_data[-1]['num']
wif_msg = ""
if ('b16' in opts and 'print_secret' in opts) \
or 'no_addresses' in opts:
wif_msg = " (wif)"
fa = "%s%%-%ss %%-%ss %%s" % (
" "*2, len(str(end)) + (0 if 'no_addresses' in opts else 1),
(5 if 'print_secret' in opts else 1) + len(wif_msg)
)
fs = " %-{}s %s".format(len(str(end)))
out = []
if not 'stdout' in opts: out.append(addrmsgs['addrfile_header'] + "\n")
out.append("# Address data checksum for {}[{}]: {}".format(
seed_id, fmt_addr_idxs(addr_idxs), addr_data_chksum))
out.append("# Record this value to a secure location\n")
if not 'no_addresses' in opts:
if not 'stdout' in opts: out.append(addrmsgs['addrfile_header'] + "\n")
out.append("# Address data checksum for {}[{}]: {}".format(
seed_id, fmt_addr_idxs(addr_idxs), addr_data_chksum))
out.append("# Record this value to a secure location\n")
out.append("%s {" % seed_id.upper())
for d in addr_data:
col1 = d['num']
if 'no_addresses' in opts:
if 'b16' in opts:
out.append(fa % (col1, " (hex):", d['sec']))
col1 = ""
out.append(fa % (col1, " (wif):", d['wif']))
if 'b16' in opts: out.append("")
elif 'print_secret' in opts:
if 'b16' in opts:
out.append(fa % (col1, "sec (hex):", d['sec']))
col1 = ""
out.append(fa % (col1, "sec"+wif_msg+":", d['wif']))
out.append(fa % ("", "addr:", d['addr']))
out.append("")
out.append(fs % (d['num'], "wif: " + d['wif']))
else:
out.append(fa % (col1, "", d['addr']))
out.append(fs % (d['num'], d['addr']))
if 'b16' in opts:
out.append(fs % ("", "hex: " + d['sec']))
if 'print_secret' in opts and not 'no_addresses' in opts:
out.append(fs % ("", "wif: " + d['wif']))
if not out[-1]: out.pop()
out.append("}")
return "\n".join(out) + "\n"
@ -191,26 +175,3 @@ def fmt_addr_idxs(addr_idxs):
prev = i
return "".join([str(i) for i in ret])
def write_addr_data_to_file(seed, addr_data_str, addr_idxs, opts):
if 'print_addresses_only' in opts: ext = g.addrfile_ext
elif 'no_addresses' in opts: ext = g.keyfile_ext
elif 'flat_list' in opts: ext = g.keylist_ext
else: ext = "akeys"
if 'b16' in opts: ext = ext.replace("keys","xkeys")
from mmgen.util import write_to_file, make_chksum_8
outfile = "{}[{}].{}".format(
make_chksum_8(seed),
fmt_addr_idxs(addr_idxs),
ext
)
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
write_to_file(outfile,addr_data_str)
dtype = "Address" if 'print_addresses_only' in opts else "Key"
msg("%s data saved to file '%s'" % (dtype,outfile))

View file

@ -19,6 +19,9 @@
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-2014'

View file

@ -420,7 +420,8 @@ def encrypt(infile,outfile="",hash_preset=''):
enc_d = encrypt_data(sha256(nonce+d).digest() + nonce + d, key,
int(ba.hexlify(iv),16))
if outfile == '-': sys.stdout.write(salt+iv+enc_d)
else: write_to_file((outfile or infile+"."+g.mmenc_ext),salt+iv+enc_d,True,True)
else: write_to_file((outfile or infile+"."+g.mmenc_ext),
salt+iv+enc_d,opts,"encrypted data",True,True)
def decrypt(infile,outfile="",hash_preset=''):
d = get_data_from_file(infile,"encrypted data")
@ -439,6 +440,6 @@ def decrypt(infile,outfile="",hash_preset=''):
import re
of = re.sub(r'\.%s$'%g.mmenc_ext,r'',infile)
if of == infile: of = infile+".dec"
write_to_file((outfile or of), out, True,True)
write_to_file((outfile or of),out,opts,"decrypted data",True,True)
else:
msg("Incorrect passphrase or hash preset")

View file

@ -19,11 +19,12 @@
tx.py: Bitcoin transaction routines
"""
from binascii import unhexlify
from mmgen.util import *
import sys, os
from binascii import unhexlify
from decimal import Decimal
import mmgen.config as g
from mmgen.util import *
txmsg = {
'not_enough_btc': "Not enough BTC in the inputs for this transaction (%s BTC)",
@ -35,9 +36,9 @@ address was specified.
NOTE: This transaction uses a mixture of both mmgen and non-mmgen inputs,
which makes the signing process more complicated. When signing the
transaction, keys for the non-mmgen inputs must be supplied in a separate
file using the '-k' option to mmgen-txsign.
file using the '-k' option to {}-txsign.
Selected mmgen inputs: %s""",
Selected mmgen inputs: %s""".format(g.proj_name.lower()),
'too_many_acct_addresses': """
ERROR: More than one address found for account: "%s".
The tracking "wallet.dat" file appears to have been altered by a non-{g.proj_name}
@ -60,8 +61,8 @@ 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 'mmgen-addrimport' and then re-run this program.
""".strip(),
watch-only wallet using '{}-addrimport' and then re-run this program.
""".strip().format(g.proj_name.lower()),
'mapping_error': """
MMGen -> BTC address mappings differ!
In transaction: %s
@ -82,12 +83,6 @@ The {pnm}-to-BTC mappings for these addresses cannot be verified!
""".strip().format(pnm=g.proj_name),
}
# Deleted text:
# Alternatively, you may import the mmgen keys into the wallet.dat of your
# offline bitcoind, first generating the required keys with mmgen-keygen and
# then running mmgen-txsign with the '-f' option to force the use of
# wallet.dat as the key source.
def connect_to_bitcoind():
@ -168,44 +163,6 @@ def get_bitcoind_cfg_options(cfg_keys):
return cfg
def write_tx_to_file(tx,sel_unspent,send_amt,b2m_map,opts):
tx_id = make_chksum_6(unhexlify(tx)).upper()
outfile = "tx_%s[%s].%s" % (tx_id,send_amt,g.rawtx_ext)
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
data = "{} {} {}\n{}\n{}\n{}\n".format(
tx_id, send_amt, make_timestamp(),
tx,
repr([i.__dict__ for i in sel_unspent]),
repr(b2m_map)
)
write_to_file(outfile,data,confirm=False)
msg("Transaction data saved to file '%s'" % outfile)
def write_signed_tx_to_file(tx,sig_tx,metadata,inputs_data,b2m_map,opts):
tx_id = make_chksum_6(unhexlify(tx)).upper()
outfile = "tx_%s[%s].%s" % (metadata[0],metadata[1],g.sigtx_ext)
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
data = "{}\n{}\n{}\n{}\n".format(
" ".join(metadata[:2] + [make_timestamp()]),
sig_tx,
repr(inputs_data),
repr(b2m_map)
)
write_to_file(outfile,data,confirm=False)
msg("Signed transaction saved to file '%s'" % outfile)
def write_sent_tx_num_to_file(tx,metadata,opts):
outfile = "tx_{}[{}].out".format(*metadata[:2])
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
write_to_file(outfile,tx+"\n",confirm=False)
msg("Transaction ID saved to file '%s'" % outfile)
def format_unspent_outputs_for_printing(out,sort_info,total):
pfs = " %-4s %-67s %-34s %-12s %-13s %-8s %-10s %s"
@ -227,7 +184,7 @@ def format_unspent_outputs_for_printing(out,sort_info,total):
)
def sort_and_view(unspent):
def sort_and_view(unspent,opts):
def s_amt(i): return i.amount
def s_txid(i): return "%s %03s" % (i.txid,i.vout)
@ -242,9 +199,9 @@ def sort_and_view(unspent):
unspent.sort(key=s_age,reverse=reverse) # Reverse age sort by default
total = trim_exponent(sum([i.amount for i in unspent]))
max_acct_len = max([len(i.account) for i in unspent])
hdr_fmt = "UNSPENT OUTPUTS (sort order: %s) Total BTC: %s"
options_msg = """
Sort options: [t]xid, [a]mount, a[d]dress, [A]ge, [r]everse, [M]mgen addr
Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
@ -253,31 +210,31 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
"('q' = quit sorting, 'p' = print to file, 'v' = pager view, 'w' = wide view): "
from copy import deepcopy
write_to_file_msg = ""
msg("")
from mmgen.term import get_terminal_size
max_acct_len = max([len(i.account) for i in unspent])
write_to_file_msg = ""
msg("")
while True:
cols = get_terminal_size()[0]
if cols < g.min_screen_width:
msg("mmgen-txcreate requires a screen at least %s characters wide" %
g.min_screen_width)
msg("%s-txcreate requires a screen at least %s characters wide" %
(g.proj_name.lower(),g.min_screen_width))
sys.exit(2)
addr_w = min(34+((1+max_acct_len) if show_mmaddr else 0),cols-46)
acct_w = min(max_acct_len, max(24,int(addr_w-10)))
btaddr_w = addr_w - acct_w - 1
tx_w = max(11,min(64, cols-addr_w-32))
txdots = "..." if tx_w < 64 else ""
fs = " %-4s %-" + str(tx_w) + "s %-2s %-" + str(addr_w) + "s %-13s %-s"
a = "Age(d)" if show_days else "Conf."
table_hdr = fs % ("Num","TX id Vout","","Address", "Amount (BTC)",a)
table_hdr = fs % ("Num","TX id Vout","","Address","Amount (BTC)",
"Age(d)" if show_days else "Conf.")
unsp = deepcopy(unspent)
for i in unsp: i.skip = ""
if group and (sort == "address" or sort == "txid"):
for n in range(len(unsp)-1):
a,b = unsp[n],unsp[n+1]
for a,b in [(unsp[i],unsp[i+1]) for i in range(len(unsp)-1)]:
if sort == "address" and a.address == b.address: b.skip = "addr"
elif sort == "txid" and a.txid == b.txid: b.skip = "txid"
@ -286,18 +243,14 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
lfill = 3 - len(amt.split(".")[0]) if "." in amt else 3 - len(amt)
i.amt = " "*lfill + amt
i.days = int(i.confirmations * g.mins_per_block / (60*24))
i.age = i.days if show_days else i.confirmations
i.mmid,i.label = parse_mmgen_label(i.account)
if i.skip == "addr":
i.addr = "|" + "." * 33
else:
if show_mmaddr and i.mmid:
acct_w = min(max_acct_len, max(24,int(addr_w-10)))
btaddr_w = addr_w - acct_w - 1
if show_mmaddr:
dots = ".." if btaddr_w < len(i.address) else ""
i.addr = "%s%s %s" % (
i.address[:btaddr_w-len(dots)],
dots,
@ -305,20 +258,17 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
else:
i.addr = i.address
dots = "..." if tx_w < 64 else ""
i.tx = " " * (tx_w-4) + "|..." if i.skip == "txid" \
else i.txid[:tx_w-len(dots)]+dots
else i.txid[:tx_w-len(txdots)]+txdots
sort_info = ["reverse"] if reverse else []
sort_info.append(sort if sort else "unsorted")
if group and (sort == "address" or sort == "txid"):
sort_info.append("grouped")
out = [hdr_fmt % (" ".join(sort_info), total), table_hdr]
for n,i in enumerate(unsp):
d = i.days if show_days else i.confirmations
out.append(fs % (str(n+1)+")",i.tx,i.vout,i.addr,i.amt,d))
out = [hdr_fmt % (" ".join(sort_info), total), table_hdr]
out += [fs % (str(n+1)+")",i.tx,i.vout,i.addr,i.amt,i.age)
for n,i in enumerate(unsp)]
msg("\n".join(out) +"\n\n" + write_to_file_msg + options_msg)
write_to_file_msg = ""
@ -344,10 +294,10 @@ Display options: show [D]ays, [g]roup, show [m]mgen addr, r[e]draw screen
elif reply == 'e': pass
elif reply == 'q': pass
elif reply == 'p':
data = format_unspent_outputs_for_printing(unsp,sort_info,total)
outfile = "listunspent[%s].out" % ",".join(sort_info)
write_to_file(outfile, data)
write_to_file_msg = "Data written to '%s'\n\n" % outfile
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_msg = "Data written to '%s'\n\n" % of
elif reply == 'v':
do_pager("\n".join(out))
continue
@ -572,16 +522,18 @@ Only ASCII printable characters are permitted.
""".strip() % (ch,label))
sys.exit(3)
def make_addr_data_chksum(addr_data):
nchars = 24
return make_chksum_N(
" ".join(["{} {}".format(*d[:2]) for d in addr_data]), nchars, sep=True
)
def check_addr_data_hash(seed_id,addr_data):
def s_addrdata(a): return int(a[0])
addr_data.sort(key=s_addrdata)
addr_data_chksum = make_chksum_8(
" ".join(["{} {}".format(*d[:2]) for d in addr_data]), sep=True
)
addr_data_chksum = make_addr_data_chksum(sorted(addr_data,key=s_addrdata))
from mmgen.addr import fmt_addr_idxs
fl = fmt_addr_idxs([int(a[0]) for a in addr_data])
msg("Computed address data checksum for '{}[{}]': {}".format(
msg("Computed checksum for addr data {}[{}]: {}".format(
seed_id,fl,addr_data_chksum))
msg("Check this value against your records")

View file

@ -24,7 +24,7 @@ from hashlib import sha256
from binascii import hexlify,unhexlify
import mmgen.config as g
from mmgen.bitcoin import b58decode_pad
from mmgen.bitcoin import b58decode_pad,b58encode_pad
from mmgen.term import *
def msg(s): sys.stderr.write(s + "\n")
@ -48,7 +48,6 @@ def get_extension(f):
import os
return os.path.splitext(f)[1][1:]
def get_random_data_from_user(uchars):
if g.quiet: msg("Enter %s random symbols" % uchars)
@ -241,6 +240,12 @@ def prompt_and_get_char(prompt,chars,enter_ok=False,verbose=False):
else: msg_r("\r")
def make_chksum_N(s,n,sep=False):
if n%4 or not (4 <= n <= 64): return False
s = sha256(sha256(s).digest()).hexdigest().upper()
sep = " " if sep else ""
return sep.join([s[i*4:i*4+4] for i in range(n/4)])
def make_chksum_8(s,sep=False):
s = sha256(sha256(s).digest()).hexdigest()[:8].upper()
return "{} {}".format(s[:4],s[4:]) if sep else s
@ -427,9 +432,9 @@ def open_file_or_exit(filename,mode):
return f
def write_to_file(outfile,data,confirm=False,verbose=False):
def write_to_file(outfile,data,opts,what="data",confirm=False,verbose=False):
if verbose: qmsg("Writing data to file '%s'" % outfile)
if 'outdir' in opts: outfile = "%s/%s" % (opts['outdir'], outfile)
if confirm:
from os import stat
@ -441,27 +446,26 @@ def write_to_file(outfile,data,confirm=False,verbose=False):
confirm_or_exit("","File '%s' already exists\nOverwrite?" % outfile)
f = open_file_or_exit(outfile,'w')
try:
f.write(data)
except:
msg("Failed to write to file '%s'" % outfile)
msg("Failed to write %s to file '%s'" % (what,outfile))
sys.exit(2)
f.close
if verbose: msg("%s written to file '%s'" % (what.capitalize(),outfile))
def export_to_file(outfile, data, label, opts):
def export_to_file(outfile, data, opts, what="data"):
if 'stdout' in opts:
write_to_stdout(data, label, confirm=True)
write_to_stdout(data, what, confirm=True)
elif not sys.stdout.isatty():
write_to_stdout(data, label, confirm=False)
write_to_stdout(data, what, confirm=False)
else:
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
write_to_file(outfile, data, confirm=False if g.quiet else True)
msg("%s saved to file '%s'" % (label.capitalize(), outfile))
c = False if g.quiet else True
write_to_file(outfile,data,opts,what,c,True)
def _display_control_data(label,metadata,hash_preset,salt,enc_seed):
@ -522,23 +526,13 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
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']
outfile="{}-{}[{},{}].{}".format(seed_id,key_id,seed_len,hash_preset,g.wallet_ext)
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
label = opts['label'] if 'label' in opts else "No Label"
from mmgen.bitcoin import b58encode_pad
metadata = seed_id.lower(),key_id.lower(),seed_len,\
pw_status,make_timestamp()
sf = b58encode_pad(salt)
esf = b58encode_pad(enc_seed)
metadata = seed_id.lower(),key_id.lower(),\
seed_len,pw_status,make_timestamp()
lines = (
label,
"{} {} {} {} {}".format(*metadata),
@ -548,23 +542,17 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
)
chk = make_chksum_6(" ".join(lines))
outfile="{}-{}[{},{}].{}".format(
seed_id,key_id,seed_len,hash_preset,g.wallet_ext)
confirm = False if g.quiet else True
write_to_file(outfile, "\n".join((chk,)+lines)+"\n", confirm)
c = False if g.quiet else True
d = "\n".join((chk,)+lines)+"\n"
write_to_file(outfile,d,opts,"wallet",c,True)
msg("Wallet saved to file '%s'" % outfile)
if g.verbose:
_display_control_data(label,metadata,hash_preset,salt,enc_seed)
def write_walletdat_dump_to_file(wallet_id,data,num_keys,ext,what,opts):
outfile = "wd_{}[{}].{}".format(wallet_id,num_keys,ext)
if 'outdir' in opts:
outfile = "%s/%s" % (opts['outdir'], outfile)
write_to_file(outfile,data,confirm=False)
msg("wallet.dat %s saved to file '%s'" % (what,outfile))
def _compare_checksums(chksum1, desc1, chksum2, desc2):
if chksum1.lower() == chksum2.lower():
@ -637,7 +625,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:
if not silent and not g.quiet:
msg("Getting {} wallet data from file '{}'".format(g.proj_name,infile))
f = open_file_or_exit(infile, 'r')
@ -864,7 +852,7 @@ def get_seed_from_incog_wallet(
passwd = get_mmgen_passphrase(prompt,opts)
msg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets)))
qmsg("Configured hash presets: %s" % " ".join(sorted(g.hash_presets)))
while True:
p = "Enter hash preset for %s wallet (default='%s'): "
hp = my_raw_input(p % (g.proj_name, g.hash_preset))