Browse Source

Input range capability added to mmgen-txcreate

philemon 11 years ago
parent
commit
caef53909e
5 changed files with 58 additions and 49 deletions
  1. 2 0
      mmgen-addrgen
  2. 13 24
      mmgen-txcreate
  3. 2 1
      mmgen/addr.py
  4. 25 15
      mmgen/tx.py
  5. 16 9
      mmgen/utils.py

+ 2 - 0
mmgen-addrgen

@@ -148,6 +148,8 @@ else: usage(help_data)
 
 addr_list = parse_address_list(addr_list_arg)
 
+if not addr_list: sys.exit(2)
+
 if not 'quiet' in opts: do_license_msg()
 
 # Interact with user:

+ 13 - 24
mmgen-txcreate

@@ -90,31 +90,21 @@ msg("Total unspent:   %s BTC" % total)
 if 'info' in opts: sys.exit(0)
 
 send_amt = sum(tx_out.values())
-msg("Total amount to spend: %s BTC" % send_amt)
-msg("%s unspent outputs total" % len(unspent))
+msg("Total amount to spend: %s BTC\n%s unspent outputs total" %
+		(send_amt, len(unspent)))
 
 while True:
 	sel_nums = select_outputs(unspent,"Choose the outputs to spend: ")
-	sel_unspent = [unspent[i] for i in sel_nums]
-	mmgen_sel,other_sel = [],[]
-	for i in sel_nums:
-		if verify_mmgen_label(unspent[i].account,check_label_len=True):
-			mmgen_sel.append(i)
-		else:
-			other_sel.append(i)
-
-	if mmgen_sel and other_sel:
-		keygen_args = [unspent[i].account.split()[0][9:] for i in mmgen_sel]
-		msg("""
-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 mmgen-txsign's '-k' option.  Alternatively, you may import the
-mmgen keys into the wallet.dat of your offline bitcoind, first running
-mmgen-keygen with address list '%s' to generate the keys.  Finally, run
-mmgen-txsign with the '-f' option to force the use of wallet.dat as the
-key source.
-""".strip() % ",".join(sorted(keygen_args)))
+	msg("Selected outputs: %s" % " ".join(str(i) for i in sel_nums))
+	sel_unspent = [unspent[i-1] for i in sel_nums]
+
+	lbls = set([verify_mmgen_label(
+				i.account,return_str=True,check_label_len=True)
+					for i in sel_unspent])
+	lbls.discard("")
+
+	if lbls and len(lbls) < len(sel_unspent):
+		msg(txmsg['mixed_inputs'] % ", ".join(sorted(lbls)))
 		if not user_confirm("Accept?"):
 			continue
 
@@ -138,8 +128,7 @@ for i in tx_out.keys(): tx_out[i] = float(tx_out[i])
 if change: tx_out[change_addr] = float(change)
 tx_hex = c.createrawtransaction(tx_in,tx_out)
 
-msg("Transaction successfully created")
-prompt = "View decoded transaction?"
+prompt = "Transaction successfully created\nView decoded transaction?"
 if user_confirm(prompt,default_yes=False):
 	view_tx_data(c,[i.__dict__ for i in sel_unspent],tx_hex)
 

+ 2 - 1
mmgen/addr.py

@@ -149,7 +149,8 @@ def format_addr_data(addrlist, seed_chksum, opts):
 # allowed characters: A-Za-z0-9, plus '{}').
 """.format(max_wallet_addr_label_len,
 		"', '".join(wallet_addr_label_symbols)).strip()
-	data = [header + "\n"]
+	data = []
+	if not 'stdout' in opts: data.append(header + "\n")
 	data.append("%s {" % seed_chksum.upper())
 
 	for el in addrlist:

+ 25 - 15
mmgen/tx.py

@@ -32,7 +32,19 @@ ERROR: This transaction produces change (%s BTC); however, no change
 address was specified.  Total inputs - transaction fee = %s BTC.
 To create a valid transaction with no change address, send this sum to the
 specified recipient address.
-""".strip()
+""".strip(),
+'mixed_inputs': """
+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 of mmgen-txsign.
+
+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.
+
+Selected mmgen inputs: %s"""
 }
 
 
@@ -321,22 +333,20 @@ def select_outputs(unspent,prompt):
 
 	while True:
 		reply = my_raw_input(prompt).strip()
-		if reply:
-			selected = []
-			try:
-				selected = [int(i) - 1 for i in reply.split()]
-			except: pass
-			else:
-				for i in selected:
-					if i < 0 or i >= len(unspent):
-						msg(
-		"Input must be a number or numbers between 1 and %s" % len(unspent))
-						break
-				else: break
 
-		msg("'%s': Invalid input" % reply)
+		if not reply: continue
+
+		from mmgen.utils import parse_address_list
+		selected = parse_address_list(reply,sep=None)
+
+		if not selected: continue
+
+		if selected[-1] > len(unspent):
+			msg("Inputs must be less than %s" % len(unspent))
+			continue
+
+		return selected
 
-	return list(set(selected))
 
 
 def make_tx_out(rcpt_arg):

+ 16 - 9
mmgen/utils.py

@@ -277,38 +277,45 @@ def check_infile(f):
 		msg("Requested input file '%s' is unreadable by you.  Aborting" % f)
 		sys.exit(1)
 
-def validate_addr_num(n):
+
+def _validate_addr_num(n):
 
 	try: n = int(n)
 	except:
 		msg("'%s': invalid argument for address" % n)
-		sys.exit(2)
+		return False
 
 	if n < 1:
 		msg("'%s': address must be greater than zero" % n)
-		sys.exit(2)
+		return False
 
 	return n
 
 
-def parse_address_list(arg):
+def parse_address_list(arg,sep=","):
 
 	ret = []
 
-	for i in (arg.split(",")):
+	for i in (arg.split(sep)):
 
 		j = i.split("-")
 
 		if len(j) == 1:
-			i = validate_addr_num(i)
+			i = _validate_addr_num(i)
+			if not i: return False
 			ret.append(i)
 		elif len(j) == 2:
-			beg = validate_addr_num(j[0])
-			end = validate_addr_num(j[1])
+			beg = _validate_addr_num(j[0])
+			if not beg: return False
+			end = _validate_addr_num(j[1])
+			if not end: return False
+			if end < beg:
+				msg("'%s-%s': end of range less than beginning" % (beg,end))
+				return False
 			for k in range(beg,end+1): ret.append(k)
 		else:
 			msg("'%s': invalid argument for address range" % j)
-			sys.exit(2)
+			return False
 
 	return sorted(set(ret))