diff --git a/mmgen-addrgen b/mmgen-addrgen index 60ca4727..c71cec0b 100755 --- a/mmgen-addrgen +++ b/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: diff --git a/mmgen-txcreate b/mmgen-txcreate index d941558b..fda40fa3 100755 --- a/mmgen-txcreate +++ b/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) + msg("Selected outputs: %s" % " ".join(str(i) for i in sel_nums)) + sel_unspent = [unspent[i-1] for i in sel_nums] - 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))) + 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) diff --git a/mmgen/addr.py b/mmgen/addr.py index d7120069..ba90bca7 100755 --- a/mmgen/addr.py +++ b/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: diff --git a/mmgen/tx.py b/mmgen/tx.py index 52f6d456..cd513535 100755 --- a/mmgen/tx.py +++ b/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): diff --git a/mmgen/utils.py b/mmgen/utils.py index 0df10776..1a0d0a8f 100755 --- a/mmgen/utils.py +++ b/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))