Browse Source

Conflicts:
mmgen-txcreate
mmgen-txsend
mmgen-txsign
mmgen/config.py
mmgen/license.py
mmgen/tx.py
mmgen/utils.py

philemon 11 years ago
parent
commit
9f852f2d86
13 changed files with 390 additions and 26 deletions
  1. 5 6
      mmgen-keygen
  2. 1 1
      mmgen-passchg
  3. 60 0
      mmgen-txcreate
  4. 66 0
      mmgen-txsend
  5. 50 0
      mmgen-txsign
  6. 1 1
      mmgen-walletchk
  7. 1 1
      mmgen-walletgen
  8. 5 5
      mmgen/addr.py
  9. 2 2
      mmgen/bitcoin.py
  10. 4 0
      mmgen/config.py
  11. 15 0
      mmgen/license.py
  12. 123 0
      mmgen/tx.py
  13. 57 10
      mmgen/utils.py

+ 5 - 6
mmgen-keygen

@@ -19,8 +19,8 @@
 """
 """
 mmgen-keygen: Generate addresses/secret keys from a mmgen deterministic 
 mmgen-keygen: Generate addresses/secret keys from a mmgen deterministic 
               wallet for a range of addresses.
               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
 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"
 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",\
 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":
 if invoked_as == "addrgen":
 	short_opts = so[0:1] + so[2:10] + so[11:]
 	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)
 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:
 # Interact with user:
-
 if invoked_as == "keygen" and not 'quiet' in opts:
 if invoked_as == "keygen" and not 'quiet' in opts:
 	confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
 	confirm_or_exit(cmessages['unencrypted_secret_keys'], 'continue')
 
 

+ 1 - 1
mmgen-passchg

@@ -48,7 +48,7 @@ NOTE: The key ID will change if either the passphrase or hash preset
 
 
 short_opts = "hd:kL:p:Pv"
 short_opts = "hd:kL:p:Pv"
 long_opts  = "help","outdir=","keep_old_passphrase","label=","hash_preset=",\
 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)
 opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
 
 

+ 60 - 0
mmgen-txcreate

@@ -36,6 +36,7 @@ help_data = {
 	'desc':    "Send BTC from specified outputs to specified addresses",
 	'desc':    "Send BTC from specified outputs to specified addresses",
 	'usage':   "[opts] <recipient address> <amount> <transaction fee> <change address>",
 	'usage':   "[opts] <recipient address> <amount> <transaction fee> <change address>",
 	'options': """
 	'options': """
+<<<<<<< HEAD
 -h, --help                 Print this help message
 -h, --help                 Print this help message
 -d, --outdir            d  Specify an alternate directory 'd' for output
 -d, --outdir            d  Specify an alternate directory 'd' for output
 -e, --echo-passphrase      Print passphrase to screen when typing it
 -e, --echo-passphrase      Print passphrase to screen when typing it
@@ -45,6 +46,21 @@ help_data = {
 
 
 short_opts = "hd:eq"
 short_opts = "hd:eq"
 long_opts  = "help","outdir=","echo_passphrase","quiet"
 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)
 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:
 elif len(cmd_args) == 3:
 	rcpt_addr,send_amt,tx_fee = cmd_args	
 	rcpt_addr,send_amt,tx_fee = cmd_args	
 	change_addr = ""
 	change_addr = ""
+<<<<<<< HEAD
 else: usage(help_data)
 else: usage(help_data)
 
 
 check_address(rcpt_addr)
 check_address(rcpt_addr)
 send_amt = check_btc_amt(send_amt)
 send_amt = check_btc_amt(send_amt)
 tx_fee   = check_btc_amt(tx_fee)
 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
 # Begin execution
 c = connect_to_bitcoind()
 c = connect_to_bitcoind()
 
 
+<<<<<<< HEAD
 if not 'quiet' in opts: do_license_msg()
 if not 'quiet' in opts: do_license_msg()
 
 
 unspent = sort_and_view(c.listunspent())
 unspent = sort_and_view(c.listunspent())
@@ -89,6 +117,34 @@ if change < 0:
 	msg(txmsg['not_enough_btc'] % change)
 	msg(txmsg['not_enough_btc'] % change)
 	sys.exit(2)
 	sys.exit(2)
 elif change > 0 and not change_addr:
 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))
 	msg(txmsg['throwaway_change'] % (change, total_in-tx_fee))
 	sys.exit(2)
 	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_out = {rcpt_addr:float(send_amt), change_addr:float(change)}
 tx_hex = c.createrawtransaction(tx_in,tx_out)
 tx_hex = c.createrawtransaction(tx_in,tx_out)
 
 
+<<<<<<< HEAD
 msg("Transaction successfully created\n")
 msg("Transaction successfully created\n")
+=======
+msg("Transaction successfully created")
+>>>>>>> my
 prompt = "View decoded transaction?"
 prompt = "View decoded transaction?"
 if user_confirm(prompt,default_yes=False):
 if user_confirm(prompt,default_yes=False):
 	view_tx_data(c,[i.__dict__ for i in sel_unspent],tx_hex)
 	view_tx_data(c,[i.__dict__ for i in sel_unspent],tx_hex)

+ 66 - 0
mmgen-txsend

@@ -20,18 +20,26 @@ mmgen-txsend: Broadcast a Bitcoin transaction to the network
 """
 """
 
 
 import sys
 import sys
+<<<<<<< HEAD
 #from hashlib import sha256
 #from hashlib import sha256
+=======
+>>>>>>> my
 
 
 from mmgen.Opts import *
 from mmgen.Opts import *
 from mmgen.license import *
 from mmgen.license import *
 from mmgen.config import *
 from mmgen.config import *
 from mmgen.tx 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_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]
 prog_name = sys.argv[0].split("/")[-1]
 
 
 help_data = {
 help_data = {
 	'prog_name': prog_name,
 	'prog_name': prog_name,
+<<<<<<< HEAD
 	'desc':    "Sign a Bitcoin transaction generated by mmgen-txcreate",
 	'desc':    "Sign a Bitcoin transaction generated by mmgen-txcreate",
 	'usage':   "[opts] <transaction file>",
 	'usage':   "[opts] <transaction file>",
 	'options': """
 	'options': """
@@ -45,6 +53,25 @@ long_opts  = "help","quiet"
 
 
 opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
 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:
 if len(cmd_args) == 1:
 	infile = cmd_args[0]
 	infile = cmd_args[0]
 	check_infile(infile)
 	check_infile(infile)
@@ -52,13 +79,27 @@ else: usage(help_data)
 
 
 # Begin execution
 # Begin execution
 
 
+<<<<<<< HEAD
 c = connect_to_bitcoind()
 c = connect_to_bitcoind()
 
 
 tx_sig = get_lines_from_file(infile,"signed transaction")[0]
 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
 from binascii import unhexlify
 try: unhexlify(tx_sig)
 try: unhexlify(tx_sig)
 except:
 except:
+<<<<<<< HEAD
 	msg("Invalid transaction data")
 	msg("Invalid transaction data")
 	sys.exit(3)
 	sys.exit(3)
 
 
@@ -70,10 +111,35 @@ msg("Sending transaction")
 
 
 try:
 try:
 	tx = c.sendrawtransaction(tx_sig)
 	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:
 except:
 	msg("Unable to send transaction")
 	msg("Unable to send transaction")
 	sys.exit(3)
 	sys.exit(3)
 
 
 msg("Transaction sent: %s" % tx)
 msg("Transaction sent: %s" % tx)
 
 
+<<<<<<< HEAD
 print_sent_tx_to_file(tx)
 print_sent_tx_to_file(tx)
+=======
+print_sent_tx_to_file(tx,metadata,opts)
+>>>>>>> my

+ 50 - 0
mmgen-txsign

@@ -35,11 +35,19 @@ help_data = {
 	'desc':    "Sign a Bitcoin transaction generated by mmgen-txcreate",
 	'desc':    "Sign a Bitcoin transaction generated by mmgen-txcreate",
 	'usage':   "[opts] <transaction file>",
 	'usage':   "[opts] <transaction file>",
 	'options': """
 	'options': """
+<<<<<<< HEAD
 -h, --help                 Print this help message
 -h, --help                 Print this help message
 -d, --outdir            d  Specify an alternate directory 'd' for output
 -d, --outdir            d  Specify an alternate directory 'd' for output
 -e, --echo-passphrase      Print passphrase to screen when typing it
 -e, --echo-passphrase      Print passphrase to screen when typing it
 -i, --info                 Just show info about the transaction and exit
 -i, --info                 Just show info about the transaction and exit
 -q, --quiet                Suppress warnings; overwrite files without asking
 -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")
 tx_data = get_lines_from_file(infile,"transaction data")
 
 
+<<<<<<< HEAD
 timestamp,tx_hex,sig_data,inputs_data = parse_tx_data(tx_data)
 timestamp,tx_hex,sig_data,inputs_data = parse_tx_data(tx_data)
 
 
 if 'info' in opts:
 if 'info' in opts:
 	view_tx_data(c,inputs_data,tx_hex,timestamp)
 	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)
 	sys.exit(0)
 
 
 if not 'quiet' in opts and not 'info' in opts: do_license_msg()
 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)
 msg("Successfully opened transaction file '%s'" % infile)
 
 
 if user_confirm("View transaction data? ",default_yes=False):
 if user_confirm("View transaction data? ",default_yes=False):
+<<<<<<< HEAD
 	view_tx_data(c,inputs_data,tx_hex,timestamp)
 	view_tx_data(c,inputs_data,tx_hex,timestamp)
 
 
 prompt = "Enter bitcoind passphrase: "
 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:
 if 'echo_passphrase' in opts:
 	password = my_raw_input(prompt)
 	password = my_raw_input(prompt)
 else:
 else:
@@ -98,6 +119,7 @@ except exceptions.WalletPassphraseIncorrect:
 	sys.exit(3)
 	sys.exit(3)
 except exceptions.WalletAlreadyUnlocked:
 except exceptions.WalletAlreadyUnlocked:
 	msg("WARNING: Wallet already unlocked!")
 	msg("WARNING: Wallet already unlocked!")
+<<<<<<< HEAD
 
 
 # signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] [sighashtype="ALL"]
 # signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] [sighashtype="ALL"]
 try:
 try:
@@ -116,3 +138,31 @@ if not sig_tx['complete']:
 prompt = "Save signed transaction?"
 prompt = "Save signed transaction?"
 if user_confirm(prompt,default_yes=True):
 if user_confirm(prompt,default_yes=True):
 	print_signed_tx_to_file(tx_hex,sig_tx['hex'],opts)
 	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

+ 1 - 1
mmgen-walletchk

@@ -43,7 +43,7 @@ help_data = {
 
 
 short_opts = "hd:emsSv"
 short_opts = "hd:emsSv"
 long_opts  = "help","outdir=","echo_passphrase","export_mnemonic",\
 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)
 opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
 
 

+ 1 - 1
mmgen-walletgen

@@ -90,7 +90,7 @@ invocations with that passphrase.
 short_opts = "hd:el:L:p:Pqu:b:ms"
 short_opts = "hd:el:L:p:Pqu:b:ms"
 long_opts  = "help","outdir=","echo_passphrase","seed_len=","label=",\
 long_opts  = "help","outdir=","echo_passphrase","seed_len=","label=",\
 		"hash_preset=","show_hash_presets","quiet","usr_randlen=",\
 		"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)
 opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts)
 
 

+ 5 - 5
mmgen/addr.py

@@ -58,10 +58,10 @@ def generate_addrs(seed, start, end, opts):
 	installed.  Otherwise an internal function is used
 	installed.  Otherwise an internal function is used
 
 
 	Supported options:
 	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:
 	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:
 	if not 'no_addresses' in opts:
@@ -121,9 +121,9 @@ def format_addr_data(addrlist, seed_chksum, opts):
 	By default, prints addresses only
 	By default, prints addresses only
 
 
 	Output can be customized with the following command line options:
 	Output can be customized with the following command line options:
-	  print_secret
-	  no_addresses
-	  b16
+		print_secret
+		no_addresses
+		b16
 	"""
 	"""
 
 
 	start = addrlist[0]['num']
 	start = addrlist[0]['num']

+ 2 - 2
mmgen/bitcoin.py

@@ -147,8 +147,8 @@ def _b58_pad(s,a,b,pad,f,w):
 	try:
 	try:
 		outlen = b[a.index(len(s))]
 		outlen = b[a.index(len(s))]
 	except:
 	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)
 		sys.exit(9)
 
 
 	out = f(s)
 	out = f(s)

+ 4 - 0
mmgen/config.py

@@ -31,7 +31,11 @@ mnemonic_lens = [i / 32 * 3 for i in seed_lens]
 from os import getenv
 from os import getenv
 debug = True if getenv("MMGEN_DEBUG") else False
 debug = True if getenv("MMGEN_DEBUG") else False
 
 
+<<<<<<< HEAD
 mins_per_block = 9
 mins_per_block = 9
+=======
+mins_per_block = 8.5
+>>>>>>> my
 passwd_max_tries = 5
 passwd_max_tries = 5
 max_randlen,min_randlen = 80,5
 max_randlen,min_randlen = 80,5
 usr_randlen = 20
 usr_randlen = 20

+ 15 - 0
mmgen/license.py

@@ -25,10 +25,17 @@ from mmgen.utils import msg, msg_r, get_char
 
 
 gpl = {
 gpl = {
 	'warning': """
 	'warning': """
+<<<<<<< HEAD
 {} Copyright (C) 2013 by Philemon <mmgen-py@yandex.com>.  This program
 {} Copyright (C) 2013 by Philemon <mmgen-py@yandex.com>.  This program
 comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
 comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
 welcome to redistribute it under certain conditions.
 welcome to redistribute it under certain conditions.
 """.format(proj_name),
 """.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': """
 	'prompt': """
 Press 'c' for conditions, 'w' for warranty info, or ENTER to continue:
 Press 'c' for conditions, 'w' for warranty info, or ENTER to continue:
 """,
 """,
@@ -629,7 +636,11 @@ def do_pager(text):
 
 
 
 
 def do_license_msg():
 def do_license_msg():
+<<<<<<< HEAD
 	msg("%s\n" % gpl['warning'].strip())
 	msg("%s\n" % gpl['warning'].strip())
+=======
+	msg(gpl['warning'])
+>>>>>>> my
 
 
 	while True:
 	while True:
 
 
@@ -638,4 +649,8 @@ def do_license_msg():
 
 
 		if   reply == 'c': do_pager(gpl['conditions'])
 		if   reply == 'c': do_pager(gpl['conditions'])
 		elif reply == 'w': do_pager(gpl['warranty'])
 		elif reply == 'w': do_pager(gpl['warranty'])
+<<<<<<< HEAD
 		else: msg("\n"); break
 		else: msg("\n"); break
+=======
+		else: msg(""); break
+>>>>>>> my

+ 123 - 0
mmgen/tx.py

@@ -50,10 +50,17 @@ def connect_to_bitcoind():
 	return c
 	return c
 
 
 
 
+<<<<<<< HEAD
 def remove_exponent(d):
 def remove_exponent(d):
     '''Remove exponent and trailing zeros.
     '''Remove exponent and trailing zeros.
     '''
     '''
     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
     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):
 def	check_address(rcpt_address):
 	from mmgen.bitcoin import verify_addr
 	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)
 		msg("%s: Too many decimal places in amount" % send_amt)
 		sys.exit(3)
 		sys.exit(3)
 	
 	
+<<<<<<< HEAD
 	return remove_exponent(retval)
 	return remove_exponent(retval)
+=======
+	return trim_exponent(retval)
+>>>>>>> my
 
 
 
 
 def get_cfg_options(cfg_keys):
 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)
 	outfile = "%s[%s].tx" % (tx_id,send_amt)
 	if 'outdir' in opts:
 	if 'outdir' in opts:
 		outfile = "%s/%s" % (opts['outdir'], outfile)
 		outfile = "%s/%s" % (opts['outdir'], outfile)
+<<<<<<< HEAD
 	input_data = sel_unspent
 	input_data = sel_unspent
 	data = "%s\n%s\n%s\n%s\n" % (
 	data = "%s\n%s\n%s\n%s\n" % (
 			make_timestamp(), tx, repr(sig_data),
 			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])
 			repr([i.__dict__ for i in sel_unspent])
 		)
 		)
 	write_to_file(outfile,data,confirm=False)
 	write_to_file(outfile,data,confirm=False)
 	msg("Transaction data saved to file '%s'" % outfile)
 	msg("Transaction data saved to file '%s'" % outfile)
 
 
 
 
+<<<<<<< HEAD
 def print_signed_tx_to_file(tx,sig_tx,opts):
 def print_signed_tx_to_file(tx,sig_tx,opts):
 	tx_id = make_chksum_8(unhexlify(tx))
 	tx_id = make_chksum_8(unhexlify(tx))
 	outfile = "%s.txsig" % tx_id
 	outfile = "%s.txsig" % tx_id
@@ -132,6 +150,26 @@ def print_sent_tx_to_file(tx):
 	write_to_file(outfile,tx+"\n",confirm=False)
 	write_to_file(outfile,tx+"\n",confirm=False)
 	msg("Transaction ID saved to file '%s'" % outfile)
 	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 sort_and_view(unspent):
 
 
 	def s_amt(a,b):  return cmp(a.amount,b.amount)
 	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_addr(a,b): return cmp(a.address,b.address)
 	def s_age(a,b):  return cmp(b.confirmations,a.confirmations)
 	def s_age(a,b):  return cmp(b.confirmations,a.confirmations)
 
 
+<<<<<<< HEAD
 	fs = "%-4s %-11s %-2s %-34s %13s"
 	fs = "%-4s %-11s %-2s %-34s %13s"
 	sort,group,reverse = "",False,False
 	sort,group,reverse = "",False,False
 
 
 	from copy import deepcopy
 	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:
 	while True:
 		out = deepcopy(unspent)
 		out = deepcopy(unspent)
 		for i in out: i.skip = ""
 		for i in out: i.skip = ""
@@ -156,11 +203,16 @@ def sort_and_view(unspent):
 					out[n+1].skip = "t"
 					out[n+1].skip = "t"
 
 
 		output = []
 		output = []
+<<<<<<< HEAD
 		output.append("Sort order: %s%s%s" % (
 		output.append("Sort order: %s%s%s" % (
+=======
+		output.append("UNSPENT OUTPUTS (sort order: %s%s%s)" % (
+>>>>>>> my
 				"reverse " if reverse else "",
 				"reverse " if reverse else "",
 				sort if sort else "None",
 				sort if sort else "None",
 	" (grouped)" if group and (sort == "address" or sort == "txid") else ""
 	" (grouped)" if group and (sort == "address" or sort == "txid") else ""
 			))
 			))
+<<<<<<< HEAD
 		output.append(fs % ("Num","TX id","Vout","Address","Amount       "))
 		output.append(fs % ("Num","TX id","Vout","Address","Amount       "))
 
 
 		for n,i in enumerate(out):
 		for n,i in enumerate(out):
@@ -170,6 +222,19 @@ def sort_and_view(unspent):
 			txid = "       |---" if i.skip == "t" else i.txid[:8]+"..."
 			txid = "       |---" if i.skip == "t" else i.txid[:8]+"..."
 
 
 			output.append(fs % (str(n+1)+")", txid,i.vout,addr,amt+(" "*fill)))
 			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:
 		while True:
 			reply = get_char("\n".join(output) +
 			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
 	return unspent
 
 
 
 
+<<<<<<< HEAD
 def view_tx_data(c,inputs_data,tx_hex,timestamp=""):
 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)
 	td = c.decoderawtransaction(tx_hex)
 
 
 	msg("TRANSACTION DATA:\n")
 	msg("TRANSACTION DATA:\n")
 
 
+<<<<<<< HEAD
 	if timestamp: msg("Timestamp: %s\n" % timestamp)
 	if timestamp: msg("Timestamp: %s\n" % timestamp)
+=======
+	if metadata: msg(
+		"Header: [ID: {}] [Amount: {} BTC] [Time: {}]\n".format(*metadata))
+>>>>>>> my
 
 
 	msg("Inputs:")
 	msg("Inputs:")
 	total_in = 0
 	total_in = 0
 	for n,i in enumerate(td['vin']):
 	for n,i in enumerate(td['vin']):
 		for j in inputs_data:
 		for j in inputs_data:
 			if j['txid'] == i['txid'] and j['vout'] == i['vout']:
 			if j['txid'] == i['txid'] and j['vout'] == i['vout']:
+<<<<<<< HEAD
 				days = j['confirmations'] * mins_per_block / (60*24)
 				days = j['confirmations'] * mins_per_block / (60*24)
 				total_in += j['amount']
 				total_in += j['amount']
 				msg("""
 				msg("""
 %-3s tx,vout: %s,%s
 %-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
     address:        %s
     amount:         %s BTC
     amount:         %s BTC
     confirmations:  %s (around %s days)
     confirmations:  %s (around %s days)
 """.strip() %
 """.strip() %
 	(n+1,i['txid'],i['vout'],j['address'],
 	(n+1,i['txid'],i['vout'],j['address'],
+<<<<<<< HEAD
 	 remove_exponent(j['amount']),j['confirmations'],days)+"\n")
 	 remove_exponent(j['amount']),j['confirmations'],days)+"\n")
 				break
 				break
 
 
 	msg("Total input: %s BTC\n" % remove_exponent(total_in))
 	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
 	total_out = 0
 	msg("Outputs:")
 	msg("Outputs:")
 	for n,i in enumerate(td['vout']):
 	for n,i in enumerate(td['vout']):
 		total_out += i['value']
 		total_out += i['value']
+<<<<<<< HEAD
  		msg("""
  		msg("""
 %-3s address: %s
 %-3s address: %s
+=======
+		msg(" " + """
+%-2s address: %s
+>>>>>>> my
     amount:  %s BTC
     amount:  %s BTC
 """.strip() % (
 """.strip() % (
 		n,
 		n,
 		i['scriptPubKey']['addresses'][0],
 		i['scriptPubKey']['addresses'][0],
+<<<<<<< HEAD
 		remove_exponent(i['value']))
 		remove_exponent(i['value']))
 	+ "\n")
 	+ "\n")
 	msg("Total output: %s BTC" % remove_exponent(total_out))
 	msg("Total output: %s BTC" % remove_exponent(total_out))
 	msg("TX fee:       %s BTC\n" % remove_exponent(total_in-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):
 def parse_tx_data(tx_data):
@@ -243,24 +343,47 @@ def parse_tx_data(tx_data):
 		msg("'%s': not a transaction file" % infile)
 		msg("'%s': not a transaction file" % infile)
 		sys.exit(2)
 		sys.exit(2)
 
 
+<<<<<<< HEAD
 	try: unhexlify(tx_data[1])
 	try: unhexlify(tx_data[1])
 	except:
 	except:
 		msg("Transaction data is invalid")
 		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)
 		sys.exit(2)
 
 
 	try:
 	try:
 		sig_data = eval(tx_data[2])
 		sig_data = eval(tx_data[2])
 	except:
 	except:
+<<<<<<< HEAD
 		msg("Signature data is invalid")
 		msg("Signature data is invalid")
+=======
+		msg(err_fmt % "signature data")
+>>>>>>> my
 		sys.exit(2)
 		sys.exit(2)
 
 
 	try:
 	try:
 		inputs_data = eval(tx_data[3])
 		inputs_data = eval(tx_data[3])
 	except:
 	except:
+<<<<<<< HEAD
 		msg("Inputs data is invalid")
 		msg("Inputs data is invalid")
 		sys.exit(2)
 		sys.exit(2)
 
 
 	return tx_data[0],tx_data[1],sig_data,inputs_data
 	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):
 def select_outputs(unspent,prompt):

+ 57 - 10
mmgen/utils.py

@@ -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()
 	m = message.strip()
 	if m: msg(m)
 	if m: msg(m)
+=======
+>>>>>>> my
 	msg("")
 	msg("")
 
 
-	conf_msg = "Type uppercase 'YES' to confirm: "
+	m = message.strip()
+	if m: msg(m)
+
+	conf_msg = "Type uppercase '%s' to confirm: " % expect
 
 
 	if question[0].isupper():
 	if question[0].isupper():
 		prompt = question + "  " + conf_msg
 		prompt = question + "  " + conf_msg
 	else:
 	else:
 		prompt = "Are you sure you want to %s?\n%s" % (question,conf_msg)
 		prompt = "Are you sure you want to %s?\n%s" % (question,conf_msg)
 
 
+<<<<<<< HEAD
 	if my_raw_input(prompt).strip() != "YES":
 	if my_raw_input(prompt).strip() != "YES":
 		msg("Program aborted by user")
 		msg("Program aborted by user")
+=======
+	if my_raw_input(prompt).strip() != expect:
+		msg("Exiting at user request")
+>>>>>>> my
 		sys.exit(2)
 		sys.exit(2)
 
 
 	msg("")
 	msg("")
@@ -313,7 +324,13 @@ no strength checking of passphrases is performed.  For an empty passphrase,
 just hit ENTER twice.
 just hit ENTER twice.
 """ % opts['hash_preset'])
 """ % 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):
 	for i in range(passwd_max_tries):
+<<<<<<< HEAD
 		if 'echo_passphrase' in opts:
 		if 'echo_passphrase' in opts:
 			return my_raw_input("Enter %s: " % what)
 			return my_raw_input("Enter %s: " % what)
 		else:
 		else:
@@ -324,8 +341,19 @@ just hit ENTER twice.
 				return ret
 				return ret
 			else:
 			else:
 				msg("%ss do not match" % what.capitalize())
 				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)
 	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)
 	N,r,p = _get_hash_params(hash_preset)
 
 
-  	import scrypt
+	import scrypt
 	return scrypt.hash(passwd, salt, 2**N, r, p, buflen=buflen)
 	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
 	Encrypt a seed for a {} deterministic wallet
 	""".format(proj_name)
 	""".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.Cipher import AES
 	from Crypto.Util import Counter
 	from Crypto.Util import Counter
 
 
 	c = AES.new(key, AES.MODE_CTR,counter=Counter.new(128))
 	c = AES.new(key, AES.MODE_CTR,counter=Counter.new(128))
 	enc_seed = c.encrypt(seed)
 	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))
 	c = AES.new(key, AES.MODE_CTR,counter=Counter.new(128))
 	dec_seed = c.decrypt(enc_seed)
 	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]),
 		("Key  ID:",             metadata[1]),
 		("Seed length:",         metadata[2]),
 		("Seed length:",         metadata[2]),
 		("Scrypt hash params:",  "Preset '%s' (%s)" % (hash_preset,
 		("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),
 		("Passphrase is empty:", pw_empty),
 		("Timestamp:",           "%s UTC" % metadata[4]),
 		("Timestamp:",           "%s UTC" % metadata[4]),
 		("Salt:",                b58encode_pad(salt)),
 		("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)
 	esf = b58encode_pad(enc_seed)
 
 
 	metadata = seed_id.lower(),key_id.lower(),\
 	metadata = seed_id.lower(),key_id.lower(),\
+<<<<<<< HEAD
 			   seed_len,pw_status,make_timestamp()
 			   seed_len,pw_status,make_timestamp()
+=======
+		seed_len,pw_status,make_timestamp()
+>>>>>>> my
 
 
 	lines = (
 	lines = (
 		label,
 		label,
@@ -593,12 +625,12 @@ def _check_chksum_6(chk,val,desc,infile):
 		msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
 		msg("Checksum: %s. Computed value: %s" % (chk,comp_chk))
 		sys.exit(2)
 		sys.exit(2)
 	elif debug:
 	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):
 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')
 	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):
 def _get_words_from_file(infile,what):
 	msg("Getting %s from file '%s'" % (what,infile))
 	msg("Getting %s from file '%s'" % (what,infile))
 	f = open_file_or_exit(infile, 'r')
 	f = open_file_or_exit(infile, 'r')
+<<<<<<< HEAD
 	lines = f.readlines(); f.close()
 	lines = f.readlines(); f.close()
+=======
+	data = f.read(); f.close()
+>>>>>>> my
 	# split() also strips
 	# 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):
 def get_lines_from_file(infile,what):
@@ -773,3 +817,6 @@ def get_seed(infile,opts,no_wallet=False):
 		return False
 		return False
 	else:
 	else:
 		return get_seed_from_wallet(infile, opts)
 		return get_seed_from_wallet(infile, opts)
+
+if __name__ == "__main__":
+	print get_lines_from_file("/tmp/lines","test file")