Longer checksum for addrfile, bugfixes, code cleanups
This commit is contained in:
parent
2a22b7d62e
commit
791fc1910f
14 changed files with 170 additions and 245 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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]",
|
||||
|
|
|
|||
|
|
@ -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': """
|
||||
|
|
|
|||
14
mmgen-tool
14
mmgen-tool
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
11
mmgen-txsend
11
mmgen-txsend
|
|
@ -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)
|
||||
|
|
|
|||
19
mmgen-txsign
19
mmgen-txsign
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
120
mmgen/tx.py
120
mmgen/tx.py
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue