Conflicts:
mmgen-txcreate mmgen-txsend mmgen-txsign mmgen/config.py mmgen/license.py mmgen/tx.py mmgen/utils.py
This commit is contained in:
parent
fbac4cceeb
commit
9f852f2d86
13 changed files with 390 additions and 26 deletions
11
mmgen-keygen
11
mmgen-keygen
|
|
@ -19,8 +19,8 @@
|
|||
"""
|
||||
mmgen-keygen: Generate addresses/secret keys from a mmgen deterministic
|
||||
wallet for a range of addresses.
|
||||
Call as 'btc-addrgen' for safe, reduced functionality
|
||||
with no output of secret keys.
|
||||
Call as 'btc-addrgen' for safe, reduced functionality
|
||||
with no output of secret keys.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
|
@ -103,8 +103,8 @@ invocations with that passphrase
|
|||
|
||||
so = "h","A","d:","e","K","l:","p:","P","q","S","v","x","b:","m","s"
|
||||
lo = "help","no_addresses","outdir=","echo_passphrase","no_keyconv",\
|
||||
"seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\
|
||||
"verbose","b16","from_brain=","from_mnemonic","from_seed"
|
||||
"seed_len=","hash_preset=","show_hash_presets","quiet","stdout",\
|
||||
"verbose","b16","from_brain=","from_mnemonic","from_seed"
|
||||
|
||||
if invoked_as == "addrgen":
|
||||
short_opts = so[0:1] + so[2:10] + so[11:]
|
||||
|
|
@ -144,10 +144,9 @@ else: usage(help_data)
|
|||
|
||||
start,end = parse_address_range(addr_range)
|
||||
|
||||
if not 'quiet' in opts: do_license_msg(); msg("\n")
|
||||
if not 'quiet' in opts: do_license_msg()
|
||||
|
||||
# Interact with user:
|
||||
|
||||
if invoked_as == "keygen" and not 'quiet' in opts:
|
||||
confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ NOTE: The key ID will change if either the passphrase or hash preset
|
|||
|
||||
short_opts = "hd:kL:p:Pv"
|
||||
long_opts = "help","outdir=","keep_old_passphrase","label=","hash_preset=",\
|
||||
"show_hash_presets","verbose"
|
||||
"show_hash_presets","verbose"
|
||||
|
||||
opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ help_data = {
|
|||
'desc': "Send BTC from specified outputs to specified addresses",
|
||||
'usage': "[opts] <recipient address> <amount> <transaction fee> <change address>",
|
||||
'options': """
|
||||
<<<<<<< HEAD
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
|
|
@ -45,6 +46,21 @@ help_data = {
|
|||
|
||||
short_opts = "hd:eq"
|
||||
long_opts = "help","outdir=","echo_passphrase","quiet"
|
||||
=======
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
-i, --info Display unspent outputs and exit
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
|
||||
Ages of transactions are approximate based on an estimated block discovery
|
||||
time of %s minutes.
|
||||
""" % mins_per_block
|
||||
}
|
||||
|
||||
short_opts = "hd:eiq"
|
||||
long_opts = "help","outdir=","echo_passphrase","info","quiet"
|
||||
>>>>>>> my
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
|
|
@ -61,15 +77,27 @@ if len(cmd_args) == 4:
|
|||
elif len(cmd_args) == 3:
|
||||
rcpt_addr,send_amt,tx_fee = cmd_args
|
||||
change_addr = ""
|
||||
<<<<<<< HEAD
|
||||
else: usage(help_data)
|
||||
|
||||
check_address(rcpt_addr)
|
||||
send_amt = check_btc_amt(send_amt)
|
||||
tx_fee = check_btc_amt(tx_fee)
|
||||
=======
|
||||
elif len(cmd_args) == 0 and 'info' in opts:
|
||||
pass
|
||||
else: usage(help_data)
|
||||
|
||||
if not 'info' in opts:
|
||||
check_address(rcpt_addr)
|
||||
send_amt = check_btc_amt(send_amt)
|
||||
tx_fee = check_btc_amt(tx_fee)
|
||||
>>>>>>> my
|
||||
|
||||
# Begin execution
|
||||
c = connect_to_bitcoind()
|
||||
|
||||
<<<<<<< HEAD
|
||||
if not 'quiet' in opts: do_license_msg()
|
||||
|
||||
unspent = sort_and_view(c.listunspent())
|
||||
|
|
@ -89,6 +117,34 @@ if change < 0:
|
|||
msg(txmsg['not_enough_btc'] % change)
|
||||
sys.exit(2)
|
||||
elif change > 0 and not change_addr:
|
||||
=======
|
||||
if not 'quiet' in opts and not 'info' in opts: do_license_msg()
|
||||
|
||||
unspent = sort_and_view(c.listunspent())
|
||||
|
||||
total = trim_exponent(sum([i.amount for i in unspent]))
|
||||
|
||||
msg("Total unspent: %s BTC" % total)
|
||||
if 'info' in opts: sys.exit(0)
|
||||
|
||||
msg("Amount to spend: %s BTC" % send_amt)
|
||||
msg("%s unspent outputs total" % len(unspent))
|
||||
|
||||
|
||||
while True:
|
||||
sel_unspent = select_outputs(unspent,"Choose the outputs to spend: ")
|
||||
total_in = trim_exponent(sum([o.amount for o in sel_unspent]))
|
||||
change = trim_exponent(total_in - (send_amt + tx_fee))
|
||||
|
||||
if change >= 0:
|
||||
prompt = "Transaction produces %s BTC in change. OK?" % change
|
||||
if user_confirm(prompt,default_yes=True):
|
||||
break
|
||||
|
||||
msg(txmsg['not_enough_btc'] % change)
|
||||
|
||||
if change > 0 and not change_addr:
|
||||
>>>>>>> my
|
||||
msg(txmsg['throwaway_change'] % (change, total_in-tx_fee))
|
||||
sys.exit(2)
|
||||
|
||||
|
|
@ -96,7 +152,11 @@ tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent]
|
|||
tx_out = {rcpt_addr:float(send_amt), change_addr:float(change)}
|
||||
tx_hex = c.createrawtransaction(tx_in,tx_out)
|
||||
|
||||
<<<<<<< HEAD
|
||||
msg("Transaction successfully created\n")
|
||||
=======
|
||||
msg("Transaction successfully created")
|
||||
>>>>>>> my
|
||||
prompt = "View decoded transaction?"
|
||||
if user_confirm(prompt,default_yes=False):
|
||||
view_tx_data(c,[i.__dict__ for i in sel_unspent],tx_hex)
|
||||
|
|
|
|||
66
mmgen-txsend
66
mmgen-txsend
|
|
@ -20,18 +20,26 @@ mmgen-txsend: Broadcast a Bitcoin transaction to the network
|
|||
"""
|
||||
|
||||
import sys
|
||||
<<<<<<< HEAD
|
||||
#from hashlib import sha256
|
||||
=======
|
||||
>>>>>>> my
|
||||
|
||||
from mmgen.Opts import *
|
||||
from mmgen.license import *
|
||||
from mmgen.config import *
|
||||
from mmgen.tx import *
|
||||
<<<<<<< HEAD
|
||||
from mmgen.utils import msg,check_infile,get_lines_from_file,confirm_or_exit
|
||||
=======
|
||||
from mmgen.utils import msg,check_opts,check_infile,get_lines_from_file,confirm_or_exit
|
||||
>>>>>>> my
|
||||
|
||||
prog_name = sys.argv[0].split("/")[-1]
|
||||
|
||||
help_data = {
|
||||
'prog_name': prog_name,
|
||||
<<<<<<< HEAD
|
||||
'desc': "Sign a Bitcoin transaction generated by mmgen-txcreate",
|
||||
'usage': "[opts] <transaction file>",
|
||||
'options': """
|
||||
|
|
@ -45,6 +53,25 @@ long_opts = "help","quiet"
|
|||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
=======
|
||||
'desc': "Send a Bitcoin transaction signed by mmgen-txsign",
|
||||
'usage': "[opts] <signed transaction file>",
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
"""
|
||||
}
|
||||
|
||||
short_opts = "hd:q"
|
||||
long_opts = "help","outdir=","quiet"
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
# Exits on invalid input
|
||||
check_opts(opts, ('outdir',))
|
||||
|
||||
>>>>>>> my
|
||||
if len(cmd_args) == 1:
|
||||
infile = cmd_args[0]
|
||||
check_infile(infile)
|
||||
|
|
@ -52,13 +79,27 @@ else: usage(help_data)
|
|||
|
||||
# Begin execution
|
||||
|
||||
<<<<<<< HEAD
|
||||
c = connect_to_bitcoind()
|
||||
|
||||
tx_sig = get_lines_from_file(infile,"signed transaction")[0]
|
||||
=======
|
||||
try:
|
||||
metadata,tx_sig = get_lines_from_file(infile,"signed transaction")
|
||||
except:
|
||||
msg("Invalid signed transaction file")
|
||||
sys.exit(3)
|
||||
|
||||
metadata = metadata.split()
|
||||
if len(metadata) != 3:
|
||||
msg("Invalid file header")
|
||||
sys.exit(3)
|
||||
>>>>>>> my
|
||||
|
||||
from binascii import unhexlify
|
||||
try: unhexlify(tx_sig)
|
||||
except:
|
||||
<<<<<<< HEAD
|
||||
msg("Invalid transaction data")
|
||||
sys.exit(3)
|
||||
|
||||
|
|
@ -70,10 +111,35 @@ msg("Sending transaction")
|
|||
|
||||
try:
|
||||
tx = c.sendrawtransaction(tx_sig)
|
||||
=======
|
||||
msg("Invalid signed transaction data")
|
||||
sys.exit(3)
|
||||
|
||||
if not 'quiet' in opts: do_license_msg()
|
||||
|
||||
msg("Signed transaction file '%s' appears valid" % infile)
|
||||
|
||||
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".upper()
|
||||
confirm_or_exit(warn, what, expect)
|
||||
|
||||
msg("Sending transaction")
|
||||
|
||||
c = connect_to_bitcoind()
|
||||
|
||||
try:
|
||||
tx = c.sendrawtransaction(tx_sig)
|
||||
# tx = "deadbeef"
|
||||
>>>>>>> my
|
||||
except:
|
||||
msg("Unable to send transaction")
|
||||
sys.exit(3)
|
||||
|
||||
msg("Transaction sent: %s" % tx)
|
||||
|
||||
<<<<<<< HEAD
|
||||
print_sent_tx_to_file(tx)
|
||||
=======
|
||||
print_sent_tx_to_file(tx,metadata,opts)
|
||||
>>>>>>> my
|
||||
|
|
|
|||
50
mmgen-txsign
50
mmgen-txsign
|
|
@ -35,11 +35,19 @@ help_data = {
|
|||
'desc': "Sign a Bitcoin transaction generated by mmgen-txcreate",
|
||||
'usage': "[opts] <transaction file>",
|
||||
'options': """
|
||||
<<<<<<< HEAD
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
-i, --info Just show info about the transaction and exit
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
=======
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Print passphrase to screen when typing it
|
||||
-i, --info Display information about the transaction and exit
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
>>>>>>> my
|
||||
"""
|
||||
}
|
||||
|
||||
|
|
@ -66,10 +74,17 @@ c = connect_to_bitcoind()
|
|||
|
||||
tx_data = get_lines_from_file(infile,"transaction data")
|
||||
|
||||
<<<<<<< HEAD
|
||||
timestamp,tx_hex,sig_data,inputs_data = parse_tx_data(tx_data)
|
||||
|
||||
if 'info' in opts:
|
||||
view_tx_data(c,inputs_data,tx_hex,timestamp)
|
||||
=======
|
||||
metadata,tx_hex,sig_data,inputs_data = parse_tx_data(tx_data)
|
||||
|
||||
if 'info' in opts:
|
||||
view_tx_data(c,inputs_data,tx_hex,metadata)
|
||||
>>>>>>> my
|
||||
sys.exit(0)
|
||||
|
||||
if not 'quiet' in opts and not 'info' in opts: do_license_msg()
|
||||
|
|
@ -77,9 +92,15 @@ if not 'quiet' in opts and not 'info' in opts: do_license_msg()
|
|||
msg("Successfully opened transaction file '%s'" % infile)
|
||||
|
||||
if user_confirm("View transaction data? ",default_yes=False):
|
||||
<<<<<<< HEAD
|
||||
view_tx_data(c,inputs_data,tx_hex,timestamp)
|
||||
|
||||
prompt = "Enter bitcoind passphrase: "
|
||||
=======
|
||||
view_tx_data(c,inputs_data,tx_hex,metadata)
|
||||
|
||||
prompt = "Enter passphrase for bitcoind wallet: "
|
||||
>>>>>>> my
|
||||
if 'echo_passphrase' in opts:
|
||||
password = my_raw_input(prompt)
|
||||
else:
|
||||
|
|
@ -98,6 +119,7 @@ except exceptions.WalletPassphraseIncorrect:
|
|||
sys.exit(3)
|
||||
except exceptions.WalletAlreadyUnlocked:
|
||||
msg("WARNING: Wallet already unlocked!")
|
||||
<<<<<<< HEAD
|
||||
|
||||
# signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] [sighashtype="ALL"]
|
||||
try:
|
||||
|
|
@ -116,3 +138,31 @@ if not sig_tx['complete']:
|
|||
prompt = "Save signed transaction?"
|
||||
if user_confirm(prompt,default_yes=True):
|
||||
print_signed_tx_to_file(tx_hex,sig_tx['hex'],opts)
|
||||
=======
|
||||
else:
|
||||
msg("Passphrase OK")
|
||||
|
||||
try:
|
||||
sig_tx = c.signrawtransaction(tx_hex,sig_data)
|
||||
# sig_tx = {'hex':"deadbeef0123456789ab",'complete':True}
|
||||
except:
|
||||
msg("Failed to sign transaction")
|
||||
if wallet_enc:
|
||||
c.walletlock()
|
||||
msg("Locking wallet")
|
||||
sys.exit(3)
|
||||
|
||||
if wallet_enc:
|
||||
c.walletlock()
|
||||
msg("Locking wallet")
|
||||
|
||||
if sig_tx['complete']:
|
||||
msg("Signing completed")
|
||||
else:
|
||||
msg("signrawtransaction() returned failure")
|
||||
sys.exit(3)
|
||||
|
||||
prompt = "Save signed transaction?"
|
||||
if user_confirm(prompt,default_yes=True):
|
||||
print_signed_tx_to_file(tx_hex,sig_tx['hex'],metadata,opts)
|
||||
>>>>>>> my
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ help_data = {
|
|||
|
||||
short_opts = "hd:emsSv"
|
||||
long_opts = "help","outdir=","echo_passphrase","export_mnemonic",\
|
||||
"export_seed","stdout","verbose"
|
||||
"export_seed","stdout","verbose"
|
||||
|
||||
opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ invocations with that passphrase.
|
|||
short_opts = "hd:el:L:p:Pqu:b:ms"
|
||||
long_opts = "help","outdir=","echo_passphrase","seed_len=","label=",\
|
||||
"hash_preset=","show_hash_presets","quiet","usr_randlen=",\
|
||||
"from_brain=","from_mnemonic","from_seed"
|
||||
"from_brain=","from_mnemonic","from_seed"
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
|
||||
|
||||
|
|
|
|||
|
|
@ -58,10 +58,10 @@ def generate_addrs(seed, start, end, opts):
|
|||
installed. Otherwise an internal function is used
|
||||
|
||||
Supported options:
|
||||
print_secret, no_addresses, no_keyconv, gen_what
|
||||
print_secret, no_addresses, no_keyconv, gen_what
|
||||
|
||||
Addresses are returned in a list of dictionaries with the following keys:
|
||||
num, sec, wif, addr
|
||||
num, sec, wif, addr
|
||||
"""
|
||||
|
||||
if not 'no_addresses' in opts:
|
||||
|
|
@ -121,9 +121,9 @@ def format_addr_data(addrlist, seed_chksum, opts):
|
|||
By default, prints addresses only
|
||||
|
||||
Output can be customized with the following command line options:
|
||||
print_secret
|
||||
no_addresses
|
||||
b16
|
||||
print_secret
|
||||
no_addresses
|
||||
b16
|
||||
"""
|
||||
|
||||
start = addrlist[0]['num']
|
||||
|
|
|
|||
|
|
@ -147,8 +147,8 @@ def _b58_pad(s,a,b,pad,f,w):
|
|||
try:
|
||||
outlen = b[a.index(len(s))]
|
||||
except:
|
||||
print "_b58_pad() accepts only %s %s bytes long "\
|
||||
"(input was %s bytes)" % (w,",".join([str(i) for i in a]),len(s))
|
||||
print "_b58_pad() accepts only %s %s bytes long "\
|
||||
"(input was %s bytes)" % (w,",".join([str(i) for i in a]),len(s))
|
||||
sys.exit(9)
|
||||
|
||||
out = f(s)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ mnemonic_lens = [i / 32 * 3 for i in seed_lens]
|
|||
from os import getenv
|
||||
debug = True if getenv("MMGEN_DEBUG") else False
|
||||
|
||||
<<<<<<< HEAD
|
||||
mins_per_block = 9
|
||||
=======
|
||||
mins_per_block = 8.5
|
||||
>>>>>>> my
|
||||
passwd_max_tries = 5
|
||||
max_randlen,min_randlen = 80,5
|
||||
usr_randlen = 20
|
||||
|
|
|
|||
|
|
@ -25,10 +25,17 @@ from mmgen.utils import msg, msg_r, get_char
|
|||
|
||||
gpl = {
|
||||
'warning': """
|
||||
<<<<<<< HEAD
|
||||
{} Copyright (C) 2013 by Philemon <mmgen-py@yandex.com>. This program
|
||||
comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
|
||||
welcome to redistribute it under certain conditions.
|
||||
""".format(proj_name),
|
||||
=======
|
||||
MMGen Copyright (C) 2013 by Philemon <mmgen-py@yandex.com>. This
|
||||
program comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
""",
|
||||
>>>>>>> my
|
||||
'prompt': """
|
||||
Press 'c' for conditions, 'w' for warranty info, or ENTER to continue:
|
||||
""",
|
||||
|
|
@ -629,7 +636,11 @@ def do_pager(text):
|
|||
|
||||
|
||||
def do_license_msg():
|
||||
<<<<<<< HEAD
|
||||
msg("%s\n" % gpl['warning'].strip())
|
||||
=======
|
||||
msg(gpl['warning'])
|
||||
>>>>>>> my
|
||||
|
||||
while True:
|
||||
|
||||
|
|
@ -638,4 +649,8 @@ def do_license_msg():
|
|||
|
||||
if reply == 'c': do_pager(gpl['conditions'])
|
||||
elif reply == 'w': do_pager(gpl['warranty'])
|
||||
<<<<<<< HEAD
|
||||
else: msg("\n"); break
|
||||
=======
|
||||
else: msg(""); break
|
||||
>>>>>>> my
|
||||
|
|
|
|||
123
mmgen/tx.py
123
mmgen/tx.py
|
|
@ -50,10 +50,17 @@ def connect_to_bitcoind():
|
|||
return c
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
def remove_exponent(d):
|
||||
'''Remove exponent and trailing zeros.
|
||||
'''
|
||||
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
|
||||
=======
|
||||
def trim_exponent(d):
|
||||
'''Remove exponent and trailing zeros.
|
||||
'''
|
||||
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
|
||||
>>>>>>> my
|
||||
|
||||
def check_address(rcpt_address):
|
||||
from mmgen.bitcoin import verify_addr
|
||||
|
|
@ -73,7 +80,11 @@ def check_btc_amt(send_amt):
|
|||
msg("%s: Too many decimal places in amount" % send_amt)
|
||||
sys.exit(3)
|
||||
|
||||
<<<<<<< HEAD
|
||||
return remove_exponent(retval)
|
||||
=======
|
||||
return trim_exponent(retval)
|
||||
>>>>>>> my
|
||||
|
||||
|
||||
def get_cfg_options(cfg_keys):
|
||||
|
|
@ -109,15 +120,22 @@ def print_tx_to_file(tx,sel_unspent,send_amt,opts):
|
|||
outfile = "%s[%s].tx" % (tx_id,send_amt)
|
||||
if 'outdir' in opts:
|
||||
outfile = "%s/%s" % (opts['outdir'], outfile)
|
||||
<<<<<<< HEAD
|
||||
input_data = sel_unspent
|
||||
data = "%s\n%s\n%s\n%s\n" % (
|
||||
make_timestamp(), tx, repr(sig_data),
|
||||
=======
|
||||
metadata = "%s %s %s" % (tx_id, send_amt, make_timestamp())
|
||||
data = "%s\n%s\n%s\n%s\n" % (
|
||||
metadata, tx, repr(sig_data),
|
||||
>>>>>>> my
|
||||
repr([i.__dict__ for i in sel_unspent])
|
||||
)
|
||||
write_to_file(outfile,data,confirm=False)
|
||||
msg("Transaction data saved to file '%s'" % outfile)
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
def print_signed_tx_to_file(tx,sig_tx,opts):
|
||||
tx_id = make_chksum_8(unhexlify(tx))
|
||||
outfile = "%s.txsig" % tx_id
|
||||
|
|
@ -132,6 +150,26 @@ def print_sent_tx_to_file(tx):
|
|||
write_to_file(outfile,tx+"\n",confirm=False)
|
||||
msg("Transaction ID saved to file '%s'" % outfile)
|
||||
|
||||
=======
|
||||
def print_signed_tx_to_file(tx,sig_tx,metadata,opts):
|
||||
tx_id = make_chksum_8(unhexlify(tx))
|
||||
outfile = "{}[{}].txsig".format(*metadata[:2])
|
||||
if 'outdir' in opts:
|
||||
outfile = "%s/%s" % (opts['outdir'], outfile)
|
||||
data = "%s\n%s\n" % (" ".join(metadata),sig_tx)
|
||||
write_to_file(outfile,data,confirm=False)
|
||||
msg("Signed transaction saved to file '%s'" % outfile)
|
||||
|
||||
|
||||
def print_sent_tx_to_file(tx,metadata,opts):
|
||||
outfile = "{}[{}].txout".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)
|
||||
|
||||
|
||||
>>>>>>> my
|
||||
def sort_and_view(unspent):
|
||||
|
||||
def s_amt(a,b): return cmp(a.amount,b.amount)
|
||||
|
|
@ -140,10 +178,19 @@ def sort_and_view(unspent):
|
|||
def s_addr(a,b): return cmp(a.address,b.address)
|
||||
def s_age(a,b): return cmp(b.confirmations,a.confirmations)
|
||||
|
||||
<<<<<<< HEAD
|
||||
fs = "%-4s %-11s %-2s %-34s %13s"
|
||||
sort,group,reverse = "",False,False
|
||||
|
||||
from copy import deepcopy
|
||||
=======
|
||||
fs = " %-4s %-11s %-2s %-34s %13s %-s"
|
||||
fs_hdr = " %-4s %-11s %-4s %-35s %-9s %-s"
|
||||
sort,group,reverse = "",False,False
|
||||
|
||||
from copy import deepcopy
|
||||
msg("")
|
||||
>>>>>>> my
|
||||
while True:
|
||||
out = deepcopy(unspent)
|
||||
for i in out: i.skip = ""
|
||||
|
|
@ -156,11 +203,16 @@ def sort_and_view(unspent):
|
|||
out[n+1].skip = "t"
|
||||
|
||||
output = []
|
||||
<<<<<<< HEAD
|
||||
output.append("Sort order: %s%s%s" % (
|
||||
=======
|
||||
output.append("UNSPENT OUTPUTS (sort order: %s%s%s)" % (
|
||||
>>>>>>> my
|
||||
"reverse " if reverse else "",
|
||||
sort if sort else "None",
|
||||
" (grouped)" if group and (sort == "address" or sort == "txid") else ""
|
||||
))
|
||||
<<<<<<< HEAD
|
||||
output.append(fs % ("Num","TX id","Vout","Address","Amount "))
|
||||
|
||||
for n,i in enumerate(out):
|
||||
|
|
@ -170,6 +222,19 @@ def sort_and_view(unspent):
|
|||
txid = " |---" if i.skip == "t" else i.txid[:8]+"..."
|
||||
|
||||
output.append(fs % (str(n+1)+")", txid,i.vout,addr,amt+(" "*fill)))
|
||||
=======
|
||||
output.append(fs_hdr % ("Num","TX id","Vout","Address","Amount",
|
||||
"Age (days)"))
|
||||
|
||||
for n,i in enumerate(out):
|
||||
amt = str(trim_exponent(i.amount))
|
||||
fill = 8 - len(amt.split(".")[-1]) if "." in amt else 9
|
||||
addr = " |" + "-"*32 if i.skip == "d" else i.address
|
||||
txid = " |---" if i.skip == "t" else i.txid[:8]+"..."
|
||||
days = int(i.confirmations * mins_per_block / (60*24))
|
||||
|
||||
output.append(fs % (str(n+1)+")", txid,i.vout,addr,amt+(" "*fill),days))
|
||||
>>>>>>> my
|
||||
|
||||
while True:
|
||||
reply = get_char("\n".join(output) +
|
||||
|
|
@ -194,47 +259,82 @@ Sort options: [t]xid, [a]mount, a[d]dress, [A]ge, [r]everse, [g]roup
|
|||
return unspent
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
def view_tx_data(c,inputs_data,tx_hex,timestamp=""):
|
||||
=======
|
||||
def view_tx_data(c,inputs_data,tx_hex,metadata=[]):
|
||||
>>>>>>> my
|
||||
|
||||
td = c.decoderawtransaction(tx_hex)
|
||||
|
||||
msg("TRANSACTION DATA:\n")
|
||||
|
||||
<<<<<<< HEAD
|
||||
if timestamp: msg("Timestamp: %s\n" % timestamp)
|
||||
=======
|
||||
if metadata: msg(
|
||||
"Header: [ID: {}] [Amount: {} BTC] [Time: {}]\n".format(*metadata))
|
||||
>>>>>>> my
|
||||
|
||||
msg("Inputs:")
|
||||
total_in = 0
|
||||
for n,i in enumerate(td['vin']):
|
||||
for j in inputs_data:
|
||||
if j['txid'] == i['txid'] and j['vout'] == i['vout']:
|
||||
<<<<<<< HEAD
|
||||
days = j['confirmations'] * mins_per_block / (60*24)
|
||||
total_in += j['amount']
|
||||
msg("""
|
||||
%-3s tx,vout: %s,%s
|
||||
=======
|
||||
days = int(j['confirmations'] * mins_per_block / (60*24))
|
||||
total_in += j['amount']
|
||||
msg(" " + """
|
||||
%-2s tx,vout: %s,%s
|
||||
>>>>>>> my
|
||||
address: %s
|
||||
amount: %s BTC
|
||||
confirmations: %s (around %s days)
|
||||
""".strip() %
|
||||
(n+1,i['txid'],i['vout'],j['address'],
|
||||
<<<<<<< HEAD
|
||||
remove_exponent(j['amount']),j['confirmations'],days)+"\n")
|
||||
break
|
||||
|
||||
msg("Total input: %s BTC\n" % remove_exponent(total_in))
|
||||
=======
|
||||
trim_exponent(j['amount']),j['confirmations'],days)+"\n")
|
||||
break
|
||||
|
||||
msg("Total input: %s BTC\n" % trim_exponent(total_in))
|
||||
>>>>>>> my
|
||||
|
||||
total_out = 0
|
||||
msg("Outputs:")
|
||||
for n,i in enumerate(td['vout']):
|
||||
total_out += i['value']
|
||||
<<<<<<< HEAD
|
||||
msg("""
|
||||
%-3s address: %s
|
||||
=======
|
||||
msg(" " + """
|
||||
%-2s address: %s
|
||||
>>>>>>> my
|
||||
amount: %s BTC
|
||||
""".strip() % (
|
||||
n,
|
||||
i['scriptPubKey']['addresses'][0],
|
||||
<<<<<<< HEAD
|
||||
remove_exponent(i['value']))
|
||||
+ "\n")
|
||||
msg("Total output: %s BTC" % remove_exponent(total_out))
|
||||
msg("TX fee: %s BTC\n" % remove_exponent(total_in-total_out))
|
||||
=======
|
||||
trim_exponent(i['value']))
|
||||
+ "\n")
|
||||
msg("Total output: %s BTC" % trim_exponent(total_out))
|
||||
msg("TX fee: %s BTC\n" % trim_exponent(total_in-total_out))
|
||||
>>>>>>> my
|
||||
|
||||
|
||||
def parse_tx_data(tx_data):
|
||||
|
|
@ -243,24 +343,47 @@ def parse_tx_data(tx_data):
|
|||
msg("'%s': not a transaction file" % infile)
|
||||
sys.exit(2)
|
||||
|
||||
<<<<<<< HEAD
|
||||
try: unhexlify(tx_data[1])
|
||||
except:
|
||||
msg("Transaction data is invalid")
|
||||
=======
|
||||
err_fmt = "Transaction %s is invalid"
|
||||
|
||||
if len(tx_data[0].split()) != 3:
|
||||
msg(err_fmt % "metadata")
|
||||
sys.exit(2)
|
||||
|
||||
try: unhexlify(tx_data[1])
|
||||
except:
|
||||
msg(err_fmt % "hex data")
|
||||
>>>>>>> my
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
sig_data = eval(tx_data[2])
|
||||
except:
|
||||
<<<<<<< HEAD
|
||||
msg("Signature data is invalid")
|
||||
=======
|
||||
msg(err_fmt % "signature data")
|
||||
>>>>>>> my
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
inputs_data = eval(tx_data[3])
|
||||
except:
|
||||
<<<<<<< HEAD
|
||||
msg("Inputs data is invalid")
|
||||
sys.exit(2)
|
||||
|
||||
return tx_data[0],tx_data[1],sig_data,inputs_data
|
||||
=======
|
||||
msg(err_fmt % "inputs data")
|
||||
sys.exit(2)
|
||||
|
||||
return tx_data[0].split(),tx_data[1],sig_data,inputs_data
|
||||
>>>>>>> my
|
||||
|
||||
|
||||
def select_outputs(unspent,prompt):
|
||||
|
|
|
|||
|
|
@ -190,21 +190,32 @@ future, you must continue using these same parameters
|
|||
"""
|
||||
}
|
||||
|
||||
def confirm_or_exit(message, question):
|
||||
def confirm_or_exit(message, question, expect="YES"):
|
||||
|
||||
<<<<<<< HEAD
|
||||
m = message.strip()
|
||||
if m: msg(m)
|
||||
=======
|
||||
>>>>>>> my
|
||||
msg("")
|
||||
|
||||
m = message.strip()
|
||||
if m: msg(m)
|
||||
msg("")
|
||||
|
||||
conf_msg = "Type uppercase 'YES' to confirm: "
|
||||
conf_msg = "Type uppercase '%s' to confirm: " % expect
|
||||
|
||||
if question[0].isupper():
|
||||
prompt = question + " " + conf_msg
|
||||
else:
|
||||
prompt = "Are you sure you want to %s?\n%s" % (question,conf_msg)
|
||||
|
||||
<<<<<<< HEAD
|
||||
if my_raw_input(prompt).strip() != "YES":
|
||||
msg("Program aborted by user")
|
||||
=======
|
||||
if my_raw_input(prompt).strip() != expect:
|
||||
msg("Exiting at user request")
|
||||
>>>>>>> my
|
||||
sys.exit(2)
|
||||
|
||||
msg("")
|
||||
|
|
@ -313,7 +324,13 @@ no strength checking of passphrases is performed. For an empty passphrase,
|
|||
just hit ENTER twice.
|
||||
""" % opts['hash_preset'])
|
||||
|
||||
if 'echo_passphrase' in opts:
|
||||
ret = " ".join(_get_words_from_user(opts,"Enter %s: " % what))
|
||||
if ret == "": msg("Empty passphrase")
|
||||
return ret
|
||||
|
||||
for i in range(passwd_max_tries):
|
||||
<<<<<<< HEAD
|
||||
if 'echo_passphrase' in opts:
|
||||
return my_raw_input("Enter %s: " % what)
|
||||
else:
|
||||
|
|
@ -324,8 +341,19 @@ just hit ENTER twice.
|
|||
return ret
|
||||
else:
|
||||
msg("%ss do not match" % what.capitalize())
|
||||
=======
|
||||
ret = " ".join(_get_words_from_user(opts,"Enter %s: " % what))
|
||||
ret2 = " ".join(_get_words_from_user(opts,"Repeat %s: " % what))
|
||||
if debug: print "Passphrases: [%s] [%s]" % (ret,ret2)
|
||||
if ret2 == ret:
|
||||
s = " (empty)" if not len(ret) else ""
|
||||
msg("%ss match%s" % (what.capitalize(),s))
|
||||
return ret
|
||||
else:
|
||||
msg("%ss do not match" % what.capitalize())
|
||||
>>>>>>> my
|
||||
|
||||
msg("User failed to duplicate passphrase in " + str(passwd_max_tries) + " attempts")
|
||||
msg("User failed to duplicate passphrase in %s attempts" % passwd_max_tries)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
|
|
@ -333,7 +361,7 @@ def _scrypt_hash_passphrase(passwd, salt, hash_preset, buflen=32):
|
|||
|
||||
N,r,p = _get_hash_params(hash_preset)
|
||||
|
||||
import scrypt
|
||||
import scrypt
|
||||
return scrypt.hash(passwd, salt, 2**N, r, p, buflen=buflen)
|
||||
|
||||
|
||||
|
|
@ -354,14 +382,14 @@ def encrypt_seed(seed, key, opts):
|
|||
Encrypt a seed for a {} deterministic wallet
|
||||
""".format(proj_name)
|
||||
|
||||
# 192-bit seed is 24 bytes -> not multiple of 16. Must use MODE_CTR
|
||||
# 192-bit seed is 24 bytes -> not multiple of 16. Must use MODE_CTR
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
|
||||
c = AES.new(key, AES.MODE_CTR,counter=Counter.new(128))
|
||||
enc_seed = c.encrypt(seed)
|
||||
|
||||
msg_r("Performing a test decryption of the seed...")
|
||||
msg_r("Performing a test decryption of the seed...")
|
||||
|
||||
c = AES.new(key, AES.MODE_CTR,counter=Counter.new(128))
|
||||
dec_seed = c.decrypt(enc_seed)
|
||||
|
|
@ -473,7 +501,7 @@ def _display_control_data(label,metadata,hash_preset,salt,enc_seed):
|
|||
("Key ID:", metadata[1]),
|
||||
("Seed length:", metadata[2]),
|
||||
("Scrypt hash params:", "Preset '%s' (%s)" % (hash_preset,
|
||||
" ".join([str(i) for i in _get_hash_params(hash_preset)]))),
|
||||
" ".join([str(i) for i in _get_hash_params(hash_preset)]))),
|
||||
("Passphrase is empty:", pw_empty),
|
||||
("Timestamp:", "%s UTC" % metadata[4]),
|
||||
("Salt:", b58encode_pad(salt)),
|
||||
|
|
@ -510,7 +538,11 @@ def write_wallet_to_file(seed, passwd, key_id, salt, enc_seed, opts):
|
|||
esf = b58encode_pad(enc_seed)
|
||||
|
||||
metadata = seed_id.lower(),key_id.lower(),\
|
||||
<<<<<<< HEAD
|
||||
seed_len,pw_status,make_timestamp()
|
||||
=======
|
||||
seed_len,pw_status,make_timestamp()
|
||||
>>>>>>> my
|
||||
|
||||
lines = (
|
||||
label,
|
||||
|
|
@ -593,12 +625,12 @@ def _check_chksum_6(chk,val,desc,infile):
|
|||
msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
|
||||
sys.exit(2)
|
||||
elif debug:
|
||||
msg("%s checksum passed: %s" % (desc.capitalize(),chk))
|
||||
msg("%s checksum passed: %s" % (desc.capitalize(),chk))
|
||||
|
||||
|
||||
def get_data_from_wallet(infile,opts):
|
||||
|
||||
msg("Getting {} wallet data from file: {}".format(proj_name,infile))
|
||||
msg("Getting {} wallet data from file '{}'".format(proj_name,infile))
|
||||
|
||||
f = open_file_or_exit(infile, 'r')
|
||||
|
||||
|
|
@ -646,9 +678,21 @@ def _get_words_from_user(opts, prompt):
|
|||
def _get_words_from_file(infile,what):
|
||||
msg("Getting %s from file '%s'" % (what,infile))
|
||||
f = open_file_or_exit(infile, 'r')
|
||||
<<<<<<< HEAD
|
||||
lines = f.readlines(); f.close()
|
||||
=======
|
||||
data = f.read(); f.close()
|
||||
>>>>>>> my
|
||||
# split() also strips
|
||||
return [w for l in lines for w in l.split()]
|
||||
return data.split()
|
||||
|
||||
|
||||
def get_lines_from_file(infile,what):
|
||||
msg("Getting %s from file '%s'" % (what,infile))
|
||||
f = open_file_or_exit(infile,'r')
|
||||
lines = f.readlines(); f.close()
|
||||
return [i.strip("\n") for i in lines]
|
||||
|
||||
|
||||
|
||||
def get_lines_from_file(infile,what):
|
||||
|
|
@ -773,3 +817,6 @@ def get_seed(infile,opts,no_wallet=False):
|
|||
return False
|
||||
else:
|
||||
return get_seed_from_wallet(infile, opts)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print get_lines_from_file("/tmp/lines","test file")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue