Input range capability added to mmgen-txcreate

This commit is contained in:
philemon 2013-12-21 22:28:38 +04:00
commit caef53909e
5 changed files with 58 additions and 49 deletions

View file

@ -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:

View file

@ -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)

View file

@ -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:

View file

@ -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):

View file

@ -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))