TX scripts updates; import address feature added
new file: mmgen-addrimport new file: mmgen/connection.py new file: mmgen/proxy.py
This commit is contained in:
parent
4912d086a2
commit
aa66a44066
17 changed files with 1278 additions and 216 deletions
3
MANIFEST
3
MANIFEST
|
|
@ -1,8 +1,10 @@
|
|||
# file GENERATED by distutils, do NOT edit
|
||||
mmgen-addrgen
|
||||
mmgen-addrimport
|
||||
mmgen-keygen
|
||||
mmgen-passchg
|
||||
mmgen-txcreate
|
||||
mmgen-txsend
|
||||
mmgen-txsign
|
||||
mmgen-walletchk
|
||||
mmgen-walletgen
|
||||
|
|
@ -12,6 +14,7 @@ mmgen/__init__.py
|
|||
mmgen/addr.py
|
||||
mmgen/bitcoin.py
|
||||
mmgen/config.py
|
||||
mmgen/connection.py
|
||||
mmgen/license.py
|
||||
mmgen/mn_electrum.py
|
||||
mmgen/mn_tirosh.py
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
mmgen-keygen
|
||||
173
mmgen-addrgen
Executable file
173
mmgen-addrgen
Executable file
|
|
@ -0,0 +1,173 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
mmgen-addrgen: Generate a range of addresses from a mmgen deterministic
|
||||
wallet.
|
||||
Call as 'btc-keygen' to allow key generation as well.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from mmgen.Opts import *
|
||||
from mmgen.config import *
|
||||
from mmgen.license import *
|
||||
from mmgen.utils import *
|
||||
from mmgen.addr import *
|
||||
|
||||
invoked_as = sys.argv[0].split("-")[-1]
|
||||
gen_what = "addresses" if invoked_as == "addrgen" else "keys"
|
||||
|
||||
if invoked_as == "keygen":
|
||||
extra_help_data = (
|
||||
"\n-A, --no-addresses Print only secret keys, no addresses",
|
||||
"\n-x, --b16 Print secret keys in hexadecimal too",
|
||||
".\nBy default, both addresses and secret keys are generated"
|
||||
)
|
||||
else: extra_help_data = ("","","")
|
||||
|
||||
help_data = {
|
||||
'prog_name': sys.argv[0].split("/")[-1],
|
||||
'desc': """Generate a range of {} from a {} wallet, mnemonic,
|
||||
seed or password""".format(gen_what,proj_name),
|
||||
'usage':"[opts] [infile] <address range>",
|
||||
'options': """
|
||||
-h, --help Print this help message{}
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Display passphrase or mnemonic on screen upon entry
|
||||
-K, --no-keyconv Use internal libraries for address generation
|
||||
instead of 'keyconv'
|
||||
-l, --seed-len N Length of seed. Options: {}
|
||||
(default: {})
|
||||
-p, --hash-preset p Use scrypt.hash() parameters from preset 'p'
|
||||
when hashing password (default: '{}')
|
||||
-P, --show-hash-presets Show information on available hash presets
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
-S, --stdout Print {W} to stdout
|
||||
-v, --verbose Produce more verbose output{}
|
||||
|
||||
-b, --from-brain l,p Generate {W} from a user-created password,
|
||||
i.e. a "brainwallet", using seed length 'l' and
|
||||
hash preset 'p' (comma-separated)
|
||||
-m, --from-mnemonic Generate {W} from an electrum-like mnemonic
|
||||
-s, --from-seed Generate {W} from a seed in .{S} format
|
||||
|
||||
Address range may be a single number or a range in the form XXX-YYY{}
|
||||
|
||||
If available, external 'keyconv' program will be used for address generation
|
||||
|
||||
Data for the --from-<what> options will be taken from <infile> if <infile>
|
||||
is specified. Otherwise, the user will be prompted to enter the data. Note
|
||||
that passphrase data in a file may be arranged in free-form fashion, using
|
||||
any combination of spaces, tabs or newlines to separate words
|
||||
|
||||
BRAINWALLET NOTE:
|
||||
|
||||
As brainwallets require especially strong hashing to thwart dictionary
|
||||
attacks, the brainwallet hash preset must be specified by the user, using
|
||||
the 'p' parameter of the '--from-brain' option
|
||||
|
||||
The '--from-brain' option also requires the user to specify a seed length
|
||||
(the 'l' parameter)
|
||||
|
||||
For a brainwallet passphrase to always generate the same keys and addresses,
|
||||
the same 'l' and 'p' parameters to '--from-brain' must be used in all future
|
||||
invocations with that passphrase
|
||||
""".format(
|
||||
extra_help_data[0],
|
||||
", ".join([str(i) for i in seed_lens]),
|
||||
seed_len,
|
||||
hash_preset,
|
||||
extra_help_data[1],
|
||||
extra_help_data[2],
|
||||
W=gen_what,
|
||||
S=seed_ext
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
if invoked_as == "addrgen":
|
||||
short_opts = so[0:1] + so[2:10] + so[11:]
|
||||
long_opts = lo[0:1] + lo[2:10] + lo[11:]
|
||||
else:
|
||||
short_opts,long_opts = so,lo
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
|
||||
|
||||
if 'show_hash_presets' in opts: show_hash_presets()
|
||||
|
||||
# Sanity checking and processing of command-line arguments:
|
||||
|
||||
opts['gen_what'] = gen_what
|
||||
|
||||
set_if_unset_and_typeconvert(opts,(
|
||||
('hash_preset',hash_preset,'str'),
|
||||
('seed_len',seed_len,'int')
|
||||
))
|
||||
|
||||
# Exits on invalid input
|
||||
check_opts(opts,('hash_preset','seed_len','outdir','from_brain'))
|
||||
|
||||
if debug:
|
||||
print "Processed options: %s" % repr(opts)
|
||||
print "Cmd args: %s" % repr(cmd_args)
|
||||
|
||||
if len(cmd_args) == 1 and (
|
||||
'from_mnemonic' in opts or
|
||||
'from_brain' in opts or
|
||||
'from_seed' in opts
|
||||
): infile,addr_range = "",cmd_args[0]
|
||||
elif len(cmd_args) == 2:
|
||||
infile,addr_range = cmd_args
|
||||
check_infile(infile)
|
||||
else: usage(help_data)
|
||||
|
||||
start,end = parse_address_range(addr_range)
|
||||
|
||||
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')
|
||||
|
||||
# Generate data:
|
||||
|
||||
if invoked_as == "addrgen":
|
||||
opts['print_addresses_only'] = True
|
||||
else:
|
||||
if not 'no_addresses' in opts: opts['print_secret'] = True
|
||||
|
||||
seed = get_seed(infile,opts)
|
||||
seed_id = make_chksum_8(seed)
|
||||
addr_data = generate_addrs(seed, start, end, opts)
|
||||
addr_data_str = format_addr_data(addr_data, seed_id, opts)
|
||||
|
||||
# Output data:
|
||||
if 'stdout' in opts:
|
||||
if invoked_as == "keygen" and not 'quiet' in opts:
|
||||
confirm = True
|
||||
else: confirm = False
|
||||
write_to_stdout(addr_data_str,"secret keys",confirm)
|
||||
elif not sys.stdout.isatty():
|
||||
write_to_stdout(addr_data_str,"secret keys",confirm=False)
|
||||
else:
|
||||
write_addr_data_to_file(seed, addr_data_str, start, end, opts)
|
||||
69
mmgen-addrimport
Executable file
69
mmgen-addrimport
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
mmgen-addrimport: Import addresses generated by mmgen-addrgen into an
|
||||
online bitcoind watching wallet.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from mmgen.Opts import *
|
||||
from mmgen.config import *
|
||||
from mmgen.license import *
|
||||
from mmgen.utils import check_infile,parse_addrs_file,confirm_or_exit
|
||||
|
||||
help_data = {
|
||||
'prog_name': sys.argv[0].split("/")[-1],
|
||||
'desc': """Import addresses generated by mmgen-addrgen into an
|
||||
online bitcoind watching wallet""",
|
||||
'usage':"[opts] [infile]",
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
-q, --quiet Suppress warnings
|
||||
-v, --verbose Produce more verbose output
|
||||
"""
|
||||
}
|
||||
|
||||
short_opts = "hqv"
|
||||
long_opts = "help", "quiet", "verbose"
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
|
||||
|
||||
if len(cmd_args) != 1: usage(help_data)
|
||||
|
||||
check_infile(cmd_args[0])
|
||||
|
||||
seed_id,addr_data = parse_addrs_file(cmd_args[0])
|
||||
|
||||
from mmgen.tx import connect_to_bitcoind
|
||||
c = connect_to_bitcoind(mmgen=True)
|
||||
|
||||
message = """
|
||||
Importing addresses can take a long time, up to 30 min. per address on a
|
||||
low-powered computer such as a netbook.
|
||||
"""
|
||||
confirm_or_exit(message, "continue", expect="YES")
|
||||
|
||||
for n,i in enumerate(addr_data):
|
||||
comment = " " + " ".join(i[2:]) if len(i) > 2 else ""
|
||||
label = "%s:%s%s" % (seed_id,str(i[0]),comment)
|
||||
msg("Importing %-6s %-34s (%s)" % (
|
||||
("%s/%s:" % (n+1,len(addr_data))),
|
||||
i[1], label)
|
||||
)
|
||||
c.importaddress(i[1],label)
|
||||
174
mmgen-keygen
174
mmgen-keygen
|
|
@ -1,174 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C) 2013 by philemon <mmgen-py@yandex.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from mmgen.Opts import *
|
||||
from mmgen.config import *
|
||||
from mmgen.license import *
|
||||
from mmgen.utils import *
|
||||
from mmgen.addr import *
|
||||
|
||||
invoked_as = sys.argv[0].split("-")[-1]
|
||||
gen_what = "addresses" if invoked_as == "addrgen" else "keys"
|
||||
|
||||
if invoked_as == "keygen":
|
||||
extra_help_data = (
|
||||
"\n-A, --no-addresses Print only secret keys, no addresses",
|
||||
"\n-x, --b16 Print secret keys in hexadecimal too",
|
||||
".\nBy default, both addresses and secret keys are generated"
|
||||
)
|
||||
else: extra_help_data = ("","","")
|
||||
|
||||
help_data = {
|
||||
'prog_name': sys.argv[0].split("/")[-1],
|
||||
'desc': """Generate a range of {} from a {} wallet, mnemonic,
|
||||
seed or password""".format(gen_what,proj_name),
|
||||
'usage':"[opts] [infile] <address range>",
|
||||
'options': """
|
||||
-h, --help Print this help message{}
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-e, --echo-passphrase Display passphrase or mnemonic on screen upon entry
|
||||
-K, --no-keyconv Use internal libraries for address generation
|
||||
instead of 'keyconv'
|
||||
-l, --seed-len N Length of seed. Options: {}
|
||||
(default: {})
|
||||
-p, --hash-preset p Use scrypt.hash() parameters from preset 'p'
|
||||
when hashing password (default: '{}')
|
||||
-P, --show-hash-presets Show information on available hash presets
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
-S, --stdout Print {W} to stdout
|
||||
-v, --verbose Produce more verbose output{}
|
||||
|
||||
-b, --from-brain l,p Generate {W} from a user-created password,
|
||||
i.e. a "brainwallet", using seed length 'l' and
|
||||
hash preset 'p' (comma-separated)
|
||||
-m, --from-mnemonic Generate {W} from an electrum-like mnemonic
|
||||
-s, --from-seed Generate {W} from a seed in .{S} format
|
||||
|
||||
Address range may be a single number or a range in the form XXX-YYY{}
|
||||
|
||||
If available, external 'keyconv' program will be used for address generation
|
||||
|
||||
Data for the --from-<what> options will be taken from <infile> if <infile>
|
||||
is specified. Otherwise, the user will be prompted to enter the data. Note
|
||||
that passphrase data in a file may be arranged in free-form fashion, using
|
||||
any combination of spaces, tabs or newlines to separate words
|
||||
|
||||
BRAINWALLET NOTE:
|
||||
|
||||
As brainwallets require especially strong hashing to thwart dictionary
|
||||
attacks, the brainwallet hash preset must be specified by the user, using
|
||||
the 'p' parameter of the '--from-brain' option
|
||||
|
||||
The '--from-brain' option also requires the user to specify a seed length
|
||||
(the 'l' parameter)
|
||||
|
||||
For a brainwallet passphrase to always generate the same keys and addresses,
|
||||
the same 'l' and 'p' parameters to '--from-brain' must be used in all future
|
||||
invocations with that passphrase
|
||||
""".format(
|
||||
extra_help_data[0],
|
||||
", ".join([str(i) for i in seed_lens]),
|
||||
seed_len,
|
||||
hash_preset,
|
||||
extra_help_data[1],
|
||||
extra_help_data[2],
|
||||
W=gen_what,
|
||||
S=seed_ext
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
if invoked_as == "addrgen":
|
||||
short_opts = so[0:1] + so[2:10] + so[11:]
|
||||
long_opts = lo[0:1] + lo[2:10] + lo[11:]
|
||||
else:
|
||||
short_opts,long_opts = so,lo
|
||||
|
||||
opts,cmd_args = process_opts(sys.argv,help_data,"".join(short_opts),long_opts)
|
||||
|
||||
if 'show_hash_presets' in opts: show_hash_presets()
|
||||
|
||||
# Sanity checking and processing of command-line arguments:
|
||||
|
||||
opts['gen_what'] = gen_what
|
||||
|
||||
set_if_unset_and_typeconvert(opts,(
|
||||
('hash_preset',hash_preset,'str'),
|
||||
('seed_len',seed_len,'int')
|
||||
))
|
||||
|
||||
# Exits on invalid input
|
||||
check_opts(opts,('hash_preset','seed_len','outdir','from_brain'))
|
||||
|
||||
if debug:
|
||||
print "Processed options: %s" % repr(opts)
|
||||
print "Cmd args: %s" % repr(cmd_args)
|
||||
|
||||
if len(cmd_args) == 1 and (
|
||||
'from_mnemonic' in opts or
|
||||
'from_brain' in opts or
|
||||
'from_seed' in opts
|
||||
): infile,addr_range = "",cmd_args[0]
|
||||
elif len(cmd_args) == 2:
|
||||
infile,addr_range = cmd_args
|
||||
check_infile(infile)
|
||||
else: usage(help_data)
|
||||
|
||||
start,end = parse_address_range(addr_range)
|
||||
|
||||
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')
|
||||
|
||||
# Generate data:
|
||||
|
||||
if invoked_as == "addrgen":
|
||||
opts['print_addresses_only'] = True
|
||||
else:
|
||||
if not 'no_addresses' in opts: opts['print_secret'] = True
|
||||
|
||||
seed = get_seed(infile,opts)
|
||||
seed_id = make_chksum_8(seed)
|
||||
addr_data = generate_addrs(seed, start, end, opts)
|
||||
addr_data_str = format_addr_data(addr_data, seed_id, opts)
|
||||
|
||||
# Output data:
|
||||
if 'stdout' in opts:
|
||||
if invoked_as == "keygen" and not 'quiet' in opts:
|
||||
confirm = True
|
||||
else: confirm = False
|
||||
write_to_stdout(addr_data_str,"secret keys",confirm)
|
||||
elif not sys.stdout.isatty():
|
||||
write_to_stdout(addr_data_str,"secret keys",confirm=False)
|
||||
else:
|
||||
write_addr_data_to_file(seed, addr_data_str, start, end, opts)
|
||||
1
mmgen-keygen
Symbolic link
1
mmgen-keygen
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
mmgen-addrgen
|
||||
|
|
@ -35,7 +35,7 @@ help_data = {
|
|||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
-k, --keep-old-passphrase Keep old passphrase (use when changing hash
|
||||
strength or label only)
|
||||
-L, --label Change the wallet's label
|
||||
-L, --label l Change the wallet's label to 'l'
|
||||
-p, --hash-preset p Change scrypt.hash() parameters to preset 'p'
|
||||
(default: '{}')
|
||||
-P, --show-hash-presets Show information on available hash presets
|
||||
|
|
@ -65,7 +65,8 @@ infile = cmd_args[0]
|
|||
# Old key:
|
||||
label,metadata,hash_preset,salt,enc_seed = get_data_from_wallet(infile,opts)
|
||||
seed_id,key_id = metadata[:2]
|
||||
passwd = " ".join(get_words("","","Enter old passphrase: ",opts))
|
||||
oldp = "" if 'keep_old_passphrase' in opts else "old "
|
||||
passwd = " ".join(get_words("","",("Enter %spassphrase: " % oldp),opts))
|
||||
key = make_key(passwd, salt, hash_preset)
|
||||
seed = decrypt_seed(enc_seed, key, seed_id, key_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
mmgen-txcreate: Send BTC from specified outputs to specified addresses
|
||||
mmgen-txcreate: Send BTC to specified addresses
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
|
@ -33,8 +33,8 @@ prog_name = sys.argv[0].split("/")[-1]
|
|||
|
||||
help_data = {
|
||||
'prog_name': prog_name,
|
||||
'desc': "Send BTC from specified outputs to specified addresses",
|
||||
'usage': "[opts] <recipient address> <amount> <transaction fee> <change address>",
|
||||
'desc': "Send BTC to specified addresses",
|
||||
'usage': "[opts] <address:amount>[,...] <transaction fee> <change address>",
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
-d, --outdir d Specify an alternate directory 'd' for output
|
||||
|
|
@ -42,6 +42,8 @@ help_data = {
|
|||
-i, --info Display unspent outputs and exit
|
||||
-q, --quiet Suppress warnings; overwrite files without asking
|
||||
|
||||
Outputs to spend are chosen by the user via a menu.
|
||||
|
||||
Ages of transactions are approximate based on an estimated block discovery
|
||||
time of %s minutes.
|
||||
""" % mins_per_block
|
||||
|
|
@ -59,19 +61,20 @@ if debug:
|
|||
print "Processed options: %s" % repr(opts)
|
||||
print "Cmd args: %s" % repr(cmd_args)
|
||||
|
||||
if len(cmd_args) == 4:
|
||||
rcpt_addr,send_amt,tx_fee,change_addr = cmd_args
|
||||
if len(cmd_args) == 3:
|
||||
rcpt_arg,tx_fee,change_addr = cmd_args
|
||||
check_address(change_addr)
|
||||
elif len(cmd_args) == 3:
|
||||
rcpt_addr,send_amt,tx_fee = cmd_args
|
||||
elif len(cmd_args) == 2:
|
||||
rcpt_arg,tx_fee = cmd_args
|
||||
change_addr = ""
|
||||
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_out = make_tx_out(rcpt_arg)
|
||||
for i in tx_out.keys(): check_address(i)
|
||||
for i in tx_out.values(): check_btc_amt(i)
|
||||
tx_fee = check_btc_amt(tx_fee)
|
||||
|
||||
# Begin execution
|
||||
|
|
@ -86,10 +89,10 @@ 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)
|
||||
send_amt = sum(tx_out.values())
|
||||
msg("Total 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]))
|
||||
|
|
@ -107,7 +110,8 @@ if change > 0 and not change_addr:
|
|||
sys.exit(2)
|
||||
|
||||
tx_in = [{"txid":i.txid, "vout":i.vout} for i in sel_unspent]
|
||||
tx_out = {rcpt_addr:float(send_amt), change_addr:float(change)}
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ confirm_or_exit(warn, what, expect)
|
|||
|
||||
msg("Sending transaction")
|
||||
|
||||
c = connect_to_bitcoind()
|
||||
c = connect_to_bitcoind(mmgen=True)
|
||||
|
||||
try:
|
||||
tx = c.sendrawtransaction(tx_sig)
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ if wallet_enc:
|
|||
if sig_tx['complete']:
|
||||
msg("Signing completed")
|
||||
else:
|
||||
msg("signrawtransaction() returned failure")
|
||||
msg("Signing failed: 'complete=%s'" % sig_tx['complete'])
|
||||
sys.exit(3)
|
||||
|
||||
prompt = "Save signed transaction?"
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ opts,cmd_args = Opts.process_opts(sys.argv,help_data,short_opts,long_opts)
|
|||
|
||||
check_opts(opts, ('outdir',))
|
||||
|
||||
if len(cmd_args) != 1:
|
||||
msg("One input file must be specified")
|
||||
sys.exit(2)
|
||||
if len(cmd_args) != 1: usage(help_data)
|
||||
|
||||
check_infile(cmd_args[0])
|
||||
|
||||
if 'export_mnemonic' in opts:
|
||||
msg("Exporting mnemonic data to file by user request")
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ b58a='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|||
# The "zero address":
|
||||
# 1111111111111111111114oLvT2 (use step2 = ("0" * 40) to generate)
|
||||
#
|
||||
def _pubhex2addr(pubhex):
|
||||
def pubhex2addr(pubhex):
|
||||
step1 = sha256(unhexlify(pubhex)).digest()
|
||||
step2 = hashlib_new('ripemd160',step1).hexdigest()
|
||||
# See above:
|
||||
|
|
@ -64,28 +64,32 @@ def _pubhex2addr(pubhex):
|
|||
def privnum2addr(numpriv):
|
||||
pko = ecdsa.SigningKey.from_secret_exponent(numpriv,secp256k1)
|
||||
pubkey = hexlify(pko.get_verifying_key().to_string())
|
||||
return _pubhex2addr('04'+pubkey)
|
||||
return pubhex2addr('04'+pubkey)
|
||||
|
||||
def verify_addr(addr):
|
||||
|
||||
if addr[0] != "1":
|
||||
print "%s Invalid address" % addr
|
||||
print "%s: Invalid address" % addr
|
||||
return False
|
||||
|
||||
addr,lz = addr[1:],0
|
||||
while addr[0] == "1": addr = addr[1:]; lz += 1
|
||||
|
||||
addr_hex = lz * "00" + hex(_b58tonum(addr))[2:].rstrip("L")
|
||||
# addr,lz = addr[1:],0
|
||||
# while addr[0] == "1": addr = addr[1:]; lz += 1
|
||||
#
|
||||
# addr_hex = lz * "00" + hex(_b58tonum(addr))[2:].rstrip("L")
|
||||
|
||||
if len(addr_hex) != 48:
|
||||
print "%s Invalid address" % addr
|
||||
return False
|
||||
# if len(addr_hex) != 48:
|
||||
# print "%s: Invalid address hex length: %s" % ("1"+addr, len(addr_hex))
|
||||
# return False
|
||||
|
||||
num = _b58tonum(addr[1:])
|
||||
if num == False: return False
|
||||
addr_hex = hex(num)[2:].rstrip("L").zfill(48)
|
||||
|
||||
step1 = sha256(unhexlify('00'+addr_hex[:40])).digest()
|
||||
step2 = sha256(step1).hexdigest()
|
||||
|
||||
if step2[:8] != addr_hex[40:]:
|
||||
print "Invalid checksum in address %s" % addr
|
||||
print "Invalid checksum in address %s" % ("1" + addr)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
|
@ -104,7 +108,7 @@ def _b58tonum(b58num):
|
|||
for i in b58num:
|
||||
if not i in b58a:
|
||||
print "Invalid symbol in b58 number: '%s'" % i
|
||||
sys.exit(9)
|
||||
return False
|
||||
|
||||
b58deconv = []
|
||||
b58num_r = b58num[::-1]
|
||||
|
|
@ -135,6 +139,7 @@ def b58decode(b58num):
|
|||
if b58num == "": return ""
|
||||
# Zap all spaces:
|
||||
num = _b58tonum(b58num.translate(None,' \t\n\r'))
|
||||
if num == False: return False
|
||||
out = hex(num)[2:].rstrip('L')
|
||||
return unhexlify("0" + out if len(out) % 2 else out)
|
||||
|
||||
|
|
@ -149,9 +154,10 @@ def _b58_pad(s,a,b,pad,f,w):
|
|||
except:
|
||||
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)
|
||||
return False
|
||||
|
||||
out = f(s)
|
||||
if out == False: return False
|
||||
return "%s%s" % (pad * (outlen - len(out)), out)
|
||||
|
||||
def b58encode_pad(s):
|
||||
|
|
@ -168,10 +174,13 @@ def b58decode_pad(s):
|
|||
# To check validity, recode with numtowif()
|
||||
def wiftonum(wifpriv):
|
||||
num = _b58tonum(wifpriv)
|
||||
if num == False: return False
|
||||
return (num % (1<<288)) >> 32
|
||||
|
||||
def wiftohex(wifpriv):
|
||||
key = hex(_b58tonum(wifpriv))[2:].rstrip('L')
|
||||
num = _b58tonum(wifpriv)
|
||||
if num == False: return False
|
||||
key = hex(num)[2:].rstrip('L')
|
||||
round1 = sha256(unhexlify(key[:66])).digest()
|
||||
round2 = sha256(round1).hexdigest()
|
||||
return key[2:66] if (key[:2] == '80' and key[66:] == round2[:8]) else False
|
||||
|
|
|
|||
737
mmgen/connection.py
Executable file
737
mmgen/connection.py
Executable file
|
|
@ -0,0 +1,737 @@
|
|||
# Copyright (c) 2010 Witchspace <witchspace81@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
"""
|
||||
Connect to Bitcoin server via JSON-RPC.
|
||||
"""
|
||||
from mmgen.proxy import JSONRPCException, AuthServiceProxy
|
||||
from bitcoinrpc.exceptions import (_wrap_exception, WalletPassphraseIncorrect,
|
||||
WalletAlreadyUnlocked)
|
||||
from bitcoinrpc.data import (ServerInfo, AccountInfo, AddressInfo,
|
||||
TransactionInfo, AddressValidation, WorkItem, MiningInfo)
|
||||
|
||||
|
||||
class MMGenBitcoinConnection(object):
|
||||
"""
|
||||
A BitcoinConnection object defines a connection to a bitcoin server.
|
||||
It is a thin wrapper around a JSON-RPC API connection.
|
||||
|
||||
Up-to-date for SVN revision 198.
|
||||
|
||||
Arguments to constructor:
|
||||
|
||||
- *user* -- Authenticate as user.
|
||||
- *password* -- Authentication password.
|
||||
- *host* -- Bitcoin JSON-RPC host.
|
||||
- *port* -- Bitcoin JSON-RPC port.
|
||||
"""
|
||||
def __init__(self, user, password, host='localhost', port=8332,
|
||||
use_https=False):
|
||||
"""
|
||||
Create a new bitcoin server connection.
|
||||
"""
|
||||
url = 'http{s}://{user}:{password}@{host}:{port}/'.format(
|
||||
s='s' if use_https else '',
|
||||
user=user, password=password, host=host, port=port)
|
||||
self.url = url
|
||||
try:
|
||||
self.proxy = AuthServiceProxy(url)
|
||||
except JSONRPCException as e:
|
||||
raise _wrap_exception(e.error)
|
||||
|
||||
# importaddress <address> [label] [rescan=true]
|
||||
def importaddress(self,address,label=None):
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
return self.proxy.importaddress(address,label)
|
||||
except JSONRPCException as e:
|
||||
raise _wrap_exception(e.error)
|
||||
|
||||
# sendrawtransaction <hex string> [allowhighfees=false]
|
||||
def sendrawtransaction(self,tx):
|
||||
"""
|
||||
"""
|
||||
try:
|
||||
return self.proxy.sendrawtransaction(tx)
|
||||
except JSONRPCException as e:
|
||||
raise _wrap_exception(e.error)
|
||||
|
||||
# def getbalance(self):
|
||||
# """
|
||||
# Stop bitcoin server.
|
||||
# """
|
||||
# try:
|
||||
# self.proxy.stop()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
# def getblock(self, hash):
|
||||
# """
|
||||
# Returns information about the given block hash.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getblock(hash)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getblockcount(self):
|
||||
# """
|
||||
# Returns the number of blocks in the longest block chain.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getblockcount()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getblockhash(self, index):
|
||||
# """
|
||||
# Returns hash of block in best-block-chain at index.
|
||||
#
|
||||
# :param index: index ob the block
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getblockhash(index)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getblocknumber(self):
|
||||
# """
|
||||
# Returns the block number of the latest block in the longest block chain.
|
||||
# Deprecated. Use getblockcount instead.
|
||||
# """
|
||||
# return self.getblockcount()
|
||||
#
|
||||
# def getconnectioncount(self):
|
||||
# """
|
||||
# Returns the number of connections to other nodes.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getconnectioncount()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getdifficulty(self):
|
||||
# """
|
||||
# Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getdifficulty()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getgenerate(self):
|
||||
# """
|
||||
# Returns :const:`True` or :const:`False`, depending on whether generation is enabled.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getgenerate()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def setgenerate(self, generate, genproclimit=None):
|
||||
# """
|
||||
# Enable or disable generation (mining) of coins.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *generate* -- is :const:`True` or :const:`False` to turn generation on or off.
|
||||
# - *genproclimit* -- Number of processors that are used for generation, -1 is unlimited.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if genproclimit is None:
|
||||
# return self.proxy.setgenerate(generate)
|
||||
# else:
|
||||
# return self.proxy.setgenerate(generate, genproclimit)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def gethashespersec(self):
|
||||
# """
|
||||
# Returns a recent hashes per second performance measurement while generating.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.gethashespersec()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getinfo(self):
|
||||
# """
|
||||
# Returns an :class:`~bitcoinrpc.data.ServerInfo` object containing various state info.
|
||||
# """
|
||||
# try:
|
||||
# return ServerInfo(**self.proxy.getinfo())
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getmininginfo(self):
|
||||
# """
|
||||
# Returns an :class:`~bitcoinrpc.data.MiningInfo` object containing various
|
||||
# mining state info.
|
||||
# """
|
||||
# try:
|
||||
# return MiningInfo(**self.proxy.getmininginfo())
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getnewaddress(self, account=None):
|
||||
# """
|
||||
# Returns a new bitcoin address for receiving payments.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *account* -- If account is specified (recommended), it is added to the address book
|
||||
# so that payments received with the address will be credited to it.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if account is None:
|
||||
# return self.proxy.getnewaddress()
|
||||
# else:
|
||||
# return self.proxy.getnewaddress(account)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getaccountaddress(self, account):
|
||||
# """
|
||||
# Returns the current bitcoin address for receiving payments to an account.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *account* -- Account for which the address should be returned.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getaccountaddress(account)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def setaccount(self, bitcoinaddress, account):
|
||||
# """
|
||||
# Sets the account associated with the given address.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *bitcoinaddress* -- Bitcoin address to associate.
|
||||
# - *account* -- Account to associate the address to.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.setaccount(bitcoinaddress, account)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getaccount(self, bitcoinaddress):
|
||||
# """
|
||||
# Returns the account associated with the given address.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *bitcoinaddress* -- Bitcoin address to get account for.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getaccount(bitcoinaddress)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getaddressesbyaccount(self, account):
|
||||
# """
|
||||
# Returns the list of addresses for the given account.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *account* -- Account to get list of addresses for.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getaddressesbyaccount(account)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def sendtoaddress(self, bitcoinaddress, amount, comment=None, comment_to=None):
|
||||
# """
|
||||
# Sends *amount* from the server's available balance to *bitcoinaddress*.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *bitcoinaddress* -- Bitcoin address to send to.
|
||||
# - *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
# - *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
# - *comment* -- Comment for transaction.
|
||||
# - *comment_to* -- Comment for to-address.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if comment is None:
|
||||
# return self.proxy.sendtoaddress(bitcoinaddress, amount)
|
||||
# elif comment_to is None:
|
||||
# return self.proxy.sendtoaddress(bitcoinaddress, amount, comment)
|
||||
# else:
|
||||
# return self.proxy.sendtoaddress(bitcoinaddress, amount, comment, comment_to)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getreceivedbyaddress(self, bitcoinaddress, minconf=1):
|
||||
# """
|
||||
# Returns the total amount received by a bitcoin address in transactions with at least a
|
||||
# certain number of confirmations.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *bitcoinaddress* -- Address to query for total amount.
|
||||
#
|
||||
# - *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getreceivedbyaddress(bitcoinaddress, minconf)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getreceivedbyaccount(self, account, minconf=1):
|
||||
# """
|
||||
# Returns the total amount received by addresses with an account in transactions with
|
||||
# at least a certain number of confirmations.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *account* -- Account to query for total amount.
|
||||
# - *minconf* -- Number of confirmations to require, defaults to 1.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.getreceivedbyaccount(account, minconf)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def gettransaction(self, txid):
|
||||
# """
|
||||
# Get detailed information about transaction
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *txid* -- Transactiond id for which the info should be returned
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return TransactionInfo(**self.proxy.gettransaction(txid))
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getrawtransaction(self, txid, verbose=True):
|
||||
# """
|
||||
# Get transaction raw info
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *txid* -- Transactiond id for which the info should be returned.
|
||||
# - *verbose* -- If False, return only the "hex" of the transaction.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if verbose:
|
||||
# return TransactionInfo(**self.proxy.getrawtransaction(txid, 1))
|
||||
# return self.proxy.getrawtransaction(txid, 0)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def createrawtransaction(self, inputs, outputs):
|
||||
# """
|
||||
# Creates a raw transaction spending given inputs
|
||||
# (a list of dictionaries, each containing a transaction id and an output number),
|
||||
# sending to given address(es).
|
||||
#
|
||||
# Returns hex-encoded raw transaction.
|
||||
#
|
||||
# Example usage:
|
||||
# >>> conn.createrawtransaction(
|
||||
# [{"txid": "a9d4599e15b53f3eb531608ddb31f48c695c3d0b3538a6bda871e8b34f2f430c",
|
||||
# "vout": 0}],
|
||||
# {"mkZBYBiq6DNoQEKakpMJegyDbw2YiNQnHT":50})
|
||||
#
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *inputs* -- A list of {"txid": txid, "vout": n} dictionaries.
|
||||
# - *outputs* -- A dictionary mapping (public) addresses to the amount
|
||||
# they are to be paid.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.createrawtransaction(inputs, outputs)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def signrawtransaction(self, hexstring, previous_transactions=None, private_keys=None):
|
||||
# """
|
||||
# Sign inputs for raw transaction (serialized, hex-encoded).
|
||||
#
|
||||
# Returns a dictionary with the keys:
|
||||
# "hex": raw transaction with signature(s) (hex-encoded string)
|
||||
# "complete": 1 if transaction has a complete set of signature(s), 0 if not
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *hexstring* -- A hex string of the transaction to sign.
|
||||
# - *previous_transactions* -- A (possibly empty) list of dictionaries of the form:
|
||||
# {"txid": txid, "vout": n, "scriptPubKey": hex, "redeemScript": hex}, representing
|
||||
# previous transaction outputs that this transaction depends on but may not yet be
|
||||
# in the block chain.
|
||||
# - *private_keys* -- A (possibly empty) list of base58-encoded private
|
||||
# keys that, if given, will be the only keys used to sign the transaction.
|
||||
# """
|
||||
# try:
|
||||
# return dict(self.proxy.signrawtransaction(hexstring, previous_transactions, private_keys))
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def decoderawtransaction(self, hexstring):
|
||||
# """
|
||||
# Produces a human-readable JSON object for a raw transaction.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *hexstring* -- A hex string of the transaction to be decoded.
|
||||
# """
|
||||
# try:
|
||||
# return dict(self.proxy.decoderawtransaction(hexstring))
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listsinceblock(self, block_hash):
|
||||
# try:
|
||||
# res = self.proxy.listsinceblock(block_hash)
|
||||
# res['transactions'] = [TransactionInfo(**x) for x in res['transactions']]
|
||||
# return res
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listreceivedbyaddress(self, minconf=1, includeempty=False):
|
||||
# """
|
||||
# Returns a list of addresses.
|
||||
#
|
||||
# Each address is represented with a :class:`~bitcoinrpc.data.AddressInfo` object.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *minconf* -- Minimum number of confirmations before payments are included.
|
||||
# - *includeempty* -- Whether to include addresses that haven't received any payments.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return [AddressInfo(**x) for x in
|
||||
# self.proxy.listreceivedbyaddress(minconf, includeempty)]
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listaccounts(self, minconf=1, as_dict=False):
|
||||
# """
|
||||
# Returns a list of account names.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *minconf* -- Minimum number of confirmations before payments are included.
|
||||
# - *as_dict* -- Returns a dictionary of account names, with their balance as values.
|
||||
# """
|
||||
# try:
|
||||
# if as_dict:
|
||||
# return dict(self.proxy.listaccounts(minconf))
|
||||
# else:
|
||||
# return self.proxy.listaccounts(minconf).keys()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listreceivedbyaccount(self, minconf=1, includeempty=False):
|
||||
# """
|
||||
# Returns a list of accounts.
|
||||
#
|
||||
# Each account is represented with a :class:`~bitcoinrpc.data.AccountInfo` object.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *minconf* -- Minimum number of confirmations before payments are included.
|
||||
#
|
||||
# - *includeempty* -- Whether to include addresses that haven't received any payments.
|
||||
# """
|
||||
# try:
|
||||
# return [AccountInfo(**x) for x in
|
||||
# self.proxy.listreceivedbyaccount(minconf, includeempty)]
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listtransactions(self, account=None, count=10, from_=0, address=None):
|
||||
# """
|
||||
# Returns a list of the last transactions for an account.
|
||||
#
|
||||
# Each transaction is represented with a :class:`~bitcoinrpc.data.TransactionInfo` object.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *account* -- Account to list transactions from. Return transactions from
|
||||
# all accounts if None.
|
||||
# - *count* -- Number of transactions to return.
|
||||
# - *from_* -- Skip the first <from_> transactions.
|
||||
# - *address* -- Receive address to consider
|
||||
# """
|
||||
# accounts = [account] if account is not None else self.listaccounts(as_dict=True).iterkeys()
|
||||
# try:
|
||||
# return [TransactionInfo(**tx) for acc in accounts for
|
||||
# tx in self.proxy.listtransactions(acc, count, from_) if
|
||||
# address is None or tx["address"] == address]
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def backupwallet(self, destination):
|
||||
# """
|
||||
# Safely copies ``wallet.dat`` to *destination*, which can be a directory or a path
|
||||
# with filename.
|
||||
#
|
||||
# Arguments:
|
||||
# - *destination* -- directory or path with filename to backup wallet to.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.backupwallet(destination)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def validateaddress(self, validateaddress):
|
||||
# """
|
||||
# Validate a bitcoin address and return information for it.
|
||||
#
|
||||
# The information is represented by a :class:`~bitcoinrpc.data.AddressValidation` object.
|
||||
#
|
||||
# Arguments: -- Address to validate.
|
||||
#
|
||||
#
|
||||
# - *validateaddress*
|
||||
# """
|
||||
# try:
|
||||
# return AddressValidation(**self.proxy.validateaddress(validateaddress))
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getbalance(self, account=None, minconf=None):
|
||||
# """
|
||||
# Get the current balance, either for an account or the total server balance.
|
||||
#
|
||||
# Arguments:
|
||||
# - *account* -- If this parameter is specified, returns the balance in the account.
|
||||
# - *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
#
|
||||
# """
|
||||
# args = []
|
||||
# if account:
|
||||
# args.append(account)
|
||||
# if minconf is not None:
|
||||
# args.append(minconf)
|
||||
# try:
|
||||
# return self.proxy.getbalance(*args)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def move(self, fromaccount, toaccount, amount, minconf=1, comment=None):
|
||||
# """
|
||||
# Move from one account in your wallet to another.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *fromaccount* -- Source account name.
|
||||
# - *toaccount* -- Destination account name.
|
||||
# - *amount* -- Amount to transfer.
|
||||
# - *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
# - *comment* -- Comment to add to transaction log.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if comment is None:
|
||||
# return self.proxy.move(fromaccount, toaccount, amount, minconf)
|
||||
# else:
|
||||
# return self.proxy.move(fromaccount, toaccount, amount, minconf, comment)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def sendfrom(self, fromaccount, tobitcoinaddress, amount, minconf=1, comment=None,
|
||||
# comment_to=None):
|
||||
# """
|
||||
# Sends amount from account's balance to bitcoinaddress. This method will fail
|
||||
# if there is less than amount bitcoins with minconf confirmations in the account's
|
||||
# balance (unless account is the empty-string-named default account; it
|
||||
# behaves like the sendtoaddress method). Returns transaction ID on success.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *fromaccount* -- Account to send from.
|
||||
# - *tobitcoinaddress* -- Bitcoin address to send to.
|
||||
# - *amount* -- Amount to send (float, rounded to the nearest 0.01).
|
||||
# - *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
# - *comment* -- Comment for transaction.
|
||||
# - *comment_to* -- Comment for to-address.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if comment is None:
|
||||
# return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf)
|
||||
# elif comment_to is None:
|
||||
# return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf, comment)
|
||||
# else:
|
||||
# return self.proxy.sendfrom(fromaccount, tobitcoinaddress, amount, minconf,
|
||||
# comment, comment_to)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def sendmany(self, fromaccount, todict, minconf=1, comment=None):
|
||||
# """
|
||||
# Sends specified amounts from account's balance to bitcoinaddresses. This method will fail
|
||||
# if there is less than total amount bitcoins with minconf confirmations in the account's
|
||||
# balance (unless account is the empty-string-named default account; Returns transaction ID
|
||||
# on success.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *fromaccount* -- Account to send from.
|
||||
# - *todict* -- Dictionary with Bitcoin addresses as keys and amounts as values.
|
||||
# - *minconf* -- Minimum number of confirmations required for transferred balance.
|
||||
# - *comment* -- Comment for transaction.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if comment is None:
|
||||
# return self.proxy.sendmany(fromaccount, todict, minconf)
|
||||
# else:
|
||||
# return self.proxy.sendmany(fromaccount, todict, minconf, comment)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def verifymessage(self, bitcoinaddress, signature, message):
|
||||
# """
|
||||
# Verifies a signature given the bitcoinaddress used to sign,
|
||||
# the signature itself, and the message that was signed.
|
||||
# Returns :const:`True` if the signature is valid, and :const:`False` if it is invalid.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *bitcoinaddress* -- the bitcoinaddress used to sign the message
|
||||
# - *signature* -- the signature to be verified
|
||||
# - *message* -- the message that was originally signed
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.verifymessage(bitcoinaddress, signature, message)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def getwork(self, data=None):
|
||||
# """
|
||||
# Get work for remote mining, or submit result.
|
||||
# If data is specified, the server tries to solve the block
|
||||
# using the provided data and returns :const:`True` if it was successful.
|
||||
# If not, the function returns formatted hash data (:class:`~bitcoinrpc.data.WorkItem`)
|
||||
# to work on.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *data* -- Result from remote mining.
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# if data is None:
|
||||
# # Only if no data provided, it returns a WorkItem
|
||||
# return WorkItem(**self.proxy.getwork())
|
||||
# else:
|
||||
# return self.proxy.getwork(data)
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def listunspent(self, minconf=1, maxconf=999999):
|
||||
# """
|
||||
# Returns a list of unspent transaction inputs in the wallet.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *minconf* -- Minimum number of confirmations required to be listed.
|
||||
#
|
||||
# - *maxconf* -- Maximal number of confirmations allowed to be listed.
|
||||
#
|
||||
#
|
||||
# """
|
||||
# try:
|
||||
# return [TransactionInfo(**tx) for tx in
|
||||
# self.proxy.listunspent(minconf, maxconf)]
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def keypoolrefill(self):
|
||||
# "Fills the keypool, requires wallet passphrase to be set."
|
||||
# try:
|
||||
# self.proxy.keypoolrefill()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def walletpassphrase(self, passphrase, timeout, dont_raise=False):
|
||||
# """
|
||||
# Stores the wallet decryption key in memory for <timeout> seconds.
|
||||
#
|
||||
# - *passphrase* -- The wallet passphrase.
|
||||
#
|
||||
# - *timeout* -- Time in seconds to keep the wallet unlocked
|
||||
# (by keeping the passphrase in memory).
|
||||
#
|
||||
# - *dont_raise* -- instead of raising `~bitcoinrpc.exceptions.WalletPassphraseIncorrect`
|
||||
# return False.
|
||||
# """
|
||||
# try:
|
||||
# self.proxy.walletpassphrase(passphrase, timeout)
|
||||
# return True
|
||||
# except JSONRPCException as e:
|
||||
# json_exception = _wrap_exception(e.error)
|
||||
# if dont_raise:
|
||||
# if isinstance(json_exception, WalletPassphraseIncorrect):
|
||||
# return False
|
||||
# elif isinstance(json_exception, WalletAlreadyUnlocked):
|
||||
# return True
|
||||
# raise json_exception
|
||||
#
|
||||
# def walletlock(self):
|
||||
# """
|
||||
# Removes the wallet encryption key from memory, locking the wallet.
|
||||
# After calling this method, you will need to call walletpassphrase
|
||||
# again before being able to call any methods which require the wallet
|
||||
# to be unlocked.
|
||||
# """
|
||||
# try:
|
||||
# return self.proxy.walletlock()
|
||||
# except JSONRPCException as e:
|
||||
# raise _wrap_exception(e.error)
|
||||
#
|
||||
# def walletpassphrasechange(self, oldpassphrase, newpassphrase, dont_raise=False):
|
||||
# """
|
||||
# Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.
|
||||
#
|
||||
# Arguments:
|
||||
#
|
||||
# - *dont_raise* -- instead of raising `~bitcoinrpc.exceptions.WalletPassphraseIncorrect`
|
||||
# return False.
|
||||
# """
|
||||
# try:
|
||||
# self.proxy.walletpassphrasechange(oldpassphrase, newpassphrase)
|
||||
# return True
|
||||
# except JSONRPCException as e:
|
||||
# json_exception = _wrap_exception(e.error)
|
||||
# if dont_raise and isinstance(json_exception, WalletPassphraseIncorrect):
|
||||
# return False
|
||||
# raise json_exception
|
||||
130
mmgen/proxy.py
Executable file
130
mmgen/proxy.py
Executable file
|
|
@ -0,0 +1,130 @@
|
|||
"""
|
||||
Copyright 2011 Jeff Garzik
|
||||
|
||||
AuthServiceProxy has the following improvements over python-jsonrpc's
|
||||
ServiceProxy class:
|
||||
|
||||
- HTTP connections persist for the life of the AuthServiceProxy object
|
||||
(if server supports HTTP/1.1)
|
||||
- sends protocol 'version', per JSON-RPC 1.1
|
||||
- sends proper, incrementing 'id'
|
||||
- sends Basic HTTP authentication headers
|
||||
- parses all JSON numbers that look like floats as Decimal
|
||||
- uses standard Python json lib
|
||||
|
||||
Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
|
||||
|
||||
Copyright (c) 2007 Jan-Klaas Kollhof
|
||||
|
||||
This file is part of jsonrpc.
|
||||
|
||||
jsonrpc is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This software is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this software; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
|
||||
try:
|
||||
import http.client as httplib
|
||||
except ImportError:
|
||||
import httplib
|
||||
import base64
|
||||
import json
|
||||
import decimal
|
||||
try:
|
||||
import urllib.parse as urlparse
|
||||
except ImportError:
|
||||
import urlparse
|
||||
|
||||
USER_AGENT = "AuthServiceProxy/0.1"
|
||||
|
||||
HTTP_TIMEOUT = 7200
|
||||
|
||||
|
||||
class JSONRPCException(Exception):
|
||||
def __init__(self, rpcError):
|
||||
Exception.__init__(self)
|
||||
self.error = rpcError
|
||||
|
||||
|
||||
class AuthServiceProxy(object):
|
||||
def __init__(self, serviceURL, serviceName=None):
|
||||
self.__serviceURL = serviceURL
|
||||
self.__serviceName = serviceName
|
||||
self.__url = urlparse.urlparse(serviceURL)
|
||||
if self.__url.port is None:
|
||||
port = 80
|
||||
else:
|
||||
port = self.__url.port
|
||||
self.__idcnt = 0
|
||||
authpair = "%s:%s" % (self.__url.username, self.__url.password)
|
||||
authpair = authpair.encode('utf8')
|
||||
self.__authhdr = "Basic ".encode('utf8') + base64.b64encode(authpair)
|
||||
if self.__url.scheme == 'https':
|
||||
self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, None, None,False,
|
||||
HTTP_TIMEOUT)
|
||||
else:
|
||||
self.__conn = httplib.HTTPConnection(self.__url.hostname, port, False,
|
||||
HTTP_TIMEOUT)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if self.__serviceName != None:
|
||||
name = "%s.%s" % (self.__serviceName, name)
|
||||
return AuthServiceProxy(self.__serviceURL, name)
|
||||
|
||||
def __call__(self, *args):
|
||||
self.__idcnt += 1
|
||||
|
||||
postdata = json.dumps({
|
||||
'version': '1.1',
|
||||
'method': self.__serviceName,
|
||||
'params': args,
|
||||
'id': self.__idcnt})
|
||||
self.__conn.request('POST', self.__url.path, postdata,
|
||||
{ 'Host' : self.__url.hostname,
|
||||
'User-Agent' : USER_AGENT,
|
||||
'Authorization' : self.__authhdr,
|
||||
'Content-type' : 'application/json' })
|
||||
|
||||
httpresp = self.__conn.getresponse()
|
||||
if httpresp is None:
|
||||
raise JSONRPCException({
|
||||
'code' : -342, 'message' : 'missing HTTP response from server'})
|
||||
|
||||
resp = httpresp.read()
|
||||
resp = resp.decode('utf8')
|
||||
resp = json.loads(resp, parse_float=decimal.Decimal)
|
||||
if 'error' in resp and resp['error'] != None:
|
||||
raise JSONRPCException(resp['error'])
|
||||
elif 'result' not in resp:
|
||||
raise JSONRPCException({
|
||||
'code' : -343, 'message' : 'missing JSON-RPC result'})
|
||||
else:
|
||||
return resp['result']
|
||||
|
||||
def _batch(self, rpc_call_list):
|
||||
postdata = json.dumps(list(rpc_call_list))
|
||||
self.__conn.request('POST', self.__url.path, postdata,
|
||||
{ 'Host' : self.__url.hostname,
|
||||
'User-Agent' : USER_AGENT,
|
||||
'Authorization' : self.__authhdr,
|
||||
'Content-type' : 'application/json' })
|
||||
|
||||
httpresp = self.__conn.getresponse()
|
||||
if httpresp is None:
|
||||
raise JSONRPCException({
|
||||
'code' : -342, 'message' : 'missing HTTP response from server'})
|
||||
|
||||
resp = httpresp.read()
|
||||
resp = resp.decode('utf8')
|
||||
resp = json.loads(resp, parse_float=decimal.Decimal)
|
||||
return resp
|
||||
35
mmgen/tx.py
35
mmgen/tx.py
|
|
@ -22,7 +22,6 @@ tx.py: Bitcoin transaction routines
|
|||
from binascii import unhexlify
|
||||
from mmgen.utils import msg,msg_r,write_to_file,my_raw_input,get_char,make_chksum_8,make_timestamp
|
||||
import sys, os
|
||||
from bitcoinrpc.connection import *
|
||||
from decimal import Decimal
|
||||
from mmgen.config import *
|
||||
|
||||
|
|
@ -36,13 +35,21 @@ specified recipient address.
|
|||
""".strip()
|
||||
}
|
||||
|
||||
def connect_to_bitcoind():
|
||||
|
||||
def connect_to_bitcoind(mmgen=False):
|
||||
|
||||
host,port,user,passwd = "localhost",8332,"rpcuser","rpcpassword"
|
||||
cfg = get_cfg_options((user,passwd))
|
||||
|
||||
if mmgen:
|
||||
import mmgen.connection
|
||||
f = mmgen.connection.MMGenBitcoinConnection
|
||||
else:
|
||||
import bitcoinrpc.connection
|
||||
f = bitcoinrpc.connection.BitcoinConnection
|
||||
|
||||
try:
|
||||
c = BitcoinConnection(cfg[user],cfg[passwd],host,port)
|
||||
c = f(cfg[user],cfg[passwd],host,port)
|
||||
except:
|
||||
msg("Unable to establish RPC connection with bitcoind")
|
||||
sys.exit(2)
|
||||
|
|
@ -55,11 +62,13 @@ def trim_exponent(d):
|
|||
'''
|
||||
return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
|
||||
|
||||
|
||||
def check_address(rcpt_address):
|
||||
from mmgen.bitcoin import verify_addr
|
||||
if not verify_addr(rcpt_address):
|
||||
sys.exit(3)
|
||||
|
||||
|
||||
def check_btc_amt(send_amt):
|
||||
|
||||
from decimal import Decimal
|
||||
|
|
@ -298,3 +307,23 @@ def select_outputs(unspent,prompt):
|
|||
msg("'%s': Invalid input" % reply)
|
||||
|
||||
return [unspent[i] for i in selected]
|
||||
|
||||
|
||||
def make_tx_out(rcpt_arg):
|
||||
|
||||
import decimal
|
||||
try:
|
||||
tx_out = dict([(i.split(":")[0],i.split(":")[1])
|
||||
for i in rcpt_arg.split(",")])
|
||||
except:
|
||||
msg("Invalid format: %s" % rcpt_arg)
|
||||
sys.exit(3)
|
||||
|
||||
try:
|
||||
for i in tx_out.keys():
|
||||
tx_out[i] = trim_exponent(Decimal(tx_out[i]))
|
||||
except decimal.InvalidOperation:
|
||||
msg("Decimal conversion error in suboption '%s:%s'" % (i,tx_out[i]))
|
||||
sys.exit(3)
|
||||
|
||||
return tx_out
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ utils.py: Shared routines for the mmgen suite
|
|||
import sys
|
||||
from mmgen.config import *
|
||||
from binascii import hexlify,unhexlify
|
||||
from mmgen.bitcoin import b58decode_pad
|
||||
|
||||
def msg(s): sys.stderr.write(s + "\n")
|
||||
def msg_r(s): sys.stderr.write(s)
|
||||
|
|
@ -628,12 +629,14 @@ def get_data_from_wallet(infile,opts):
|
|||
sys.exit(9)
|
||||
|
||||
res = {}
|
||||
from mmgen.bitcoin import b58decode_pad
|
||||
for i,key in (4,"salt"),(5,"enc_seed"):
|
||||
l = lines[i].split()
|
||||
val = "".join(l[1:])
|
||||
_check_chksum_6(l[0], val, key, infile)
|
||||
res[key] = b58decode_pad(val)
|
||||
if res[key] == False:
|
||||
msg("Invalid b58 number: %s" % val)
|
||||
sys.exit(9)
|
||||
|
||||
_check_chksum_6(lines[0], " ".join(lines[1:]), "Master", infile)
|
||||
|
||||
|
|
@ -683,8 +686,11 @@ def get_seed_from_seed_data(words):
|
|||
msg_r("Validating %s checksum..." % seed_ext)
|
||||
|
||||
if compare_checksums(chk, "from seed", stored_chk, "from input"):
|
||||
from mmgen.bitcoin import b58decode_pad
|
||||
seed = b58decode_pad(seed_b58)
|
||||
if seed == False:
|
||||
msg("Invalid b58 number: %s" % val)
|
||||
sys.exit(9)
|
||||
|
||||
msg("%s data produces seed ID: %s" % (seed_ext,make_chksum_8(seed)))
|
||||
return seed
|
||||
else:
|
||||
|
|
@ -778,5 +784,60 @@ def get_seed(infile,opts,no_wallet=False):
|
|||
else:
|
||||
return get_seed_from_wallet(infile, opts)
|
||||
|
||||
def remove_blanks_comments(lines):
|
||||
import re
|
||||
# re.sub(pattern, repl, string, count=0, flags=0)
|
||||
ret = []
|
||||
for i in lines:
|
||||
i = re.sub('#.*','',i,1)
|
||||
i = re.sub('\s+$','',i)
|
||||
if i: ret.append(i)
|
||||
|
||||
return ret
|
||||
|
||||
def parse_addrs_file(f):
|
||||
lines = get_lines_from_file(f,"address data")
|
||||
lines = remove_blanks_comments(lines)
|
||||
|
||||
seed_id,obrace = lines[0].split()
|
||||
cbrace = lines[-1]
|
||||
|
||||
if obrace != '{':
|
||||
msg("'%s': invalid first line" % lines[0])
|
||||
elif cbrace != '}':
|
||||
msg("'%s': invalid last line" % cbrace)
|
||||
elif len(seed_id) != 8:
|
||||
msg("'%s': invalid Seed ID" % seed_id)
|
||||
else:
|
||||
try:
|
||||
unhexlify(seed_id)
|
||||
except:
|
||||
msg("'%s': invalid Seed ID" % seed_id)
|
||||
sys.exit(3)
|
||||
|
||||
ret = []
|
||||
for i in lines[1:-1]:
|
||||
d = i.split()
|
||||
|
||||
try: d[0] = int(d[0])
|
||||
except:
|
||||
msg("'%s': invalid address num. in line: %s" % (d[0],d))
|
||||
sys.exit(3)
|
||||
|
||||
from mmgen.bitcoin import verify_addr
|
||||
if not verify_addr(d[1]):
|
||||
msg("'%s': invalid address" % d[1])
|
||||
sys.exit(3)
|
||||
|
||||
ret.append(d)
|
||||
|
||||
return seed_id,ret
|
||||
|
||||
sys.exit(3)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print get_lines_from_file("/tmp/lines","test file")
|
||||
|
|
|
|||
3
scripts/deinstall.sh
Executable file
3
scripts/deinstall.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
set -x
|
||||
sudo rm -r /usr/local/bin/mmgen-* /usr/local/lib/python2.7/dist-packages/mmgen*
|
||||
18
setup.py
18
setup.py
|
|
@ -3,7 +3,7 @@ from distutils.core import setup
|
|||
|
||||
setup(
|
||||
name = 'mmgen',
|
||||
version = '0.6.1',
|
||||
version = '0.6.2',
|
||||
author = 'Philemon',
|
||||
author_email = 'mmgen-py@yandex.com',
|
||||
url = 'https://github.com/mmgen/mmgen',
|
||||
|
|
@ -19,15 +19,27 @@ setup(
|
|||
'mmgen.Opts',
|
||||
'mmgen.tx',
|
||||
'mmgen.utils',
|
||||
'mmgen.walletgen'
|
||||
'mmgen.walletgen',
|
||||
'mmgen.connection',
|
||||
'mmgen.proxy',
|
||||
'tests.addr',
|
||||
'tests.bitcoin',
|
||||
'tests.mn_electrum',
|
||||
'tests.mnemonic',
|
||||
'tests.mn_tirosh',
|
||||
'tests.test',
|
||||
'tests.utils',
|
||||
'tests.walletgen'
|
||||
],
|
||||
data_files=[('/usr/local/bin', [
|
||||
'mmgen-addrgen',
|
||||
'mmgen-addrimport',
|
||||
'mmgen-keygen',
|
||||
'mmgen-passchg',
|
||||
'mmgen-walletchk',
|
||||
'mmgen-walletgen',
|
||||
'mmgen-txcreate',
|
||||
'mmgen-txsign'
|
||||
'mmgen-txsign',
|
||||
'mmgen-txsend'
|
||||
])]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -168,6 +168,10 @@ def hextosha256(s_in):
|
|||
s_enc = sha256(unhexlify(s_in)).hexdigest()
|
||||
print "Encoded data: %s" % s_enc
|
||||
|
||||
def pubhextoaddr(s_in):
|
||||
print "Entered data: %s" % s_in
|
||||
s_enc = pubhex2addr(s_in)
|
||||
print "Encoded data: %s" % s_enc
|
||||
|
||||
tests = {
|
||||
"keyconv_compare": ['wif [str]','quiet [bool=False]'],
|
||||
|
|
@ -183,6 +187,7 @@ tests = {
|
|||
"numtowif_rand": ['quiet [bool=False]'],
|
||||
"hextosha256": ['hexnum [str]','quiet [bool=False]'],
|
||||
"hextowiftopubkey": ['hexnum [str]','quiet [bool=False]'],
|
||||
"pubhextoaddr": ['hexnum [str]','quiet [bool=False]'],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue