From 3897ec329709bffa386c154dba798653333e613e Mon Sep 17 00:00:00 2001 From: philemon Date: Mon, 14 Nov 2016 14:45:08 +0300 Subject: [PATCH] Version 0.8.7a --testnet option added to all relevant scripts utility scripts under scripts/ updated --- MANIFEST.in | 6 +++ mmgen/globalvars.py | 16 ++++--- mmgen/main_addrgen.py | 3 +- mmgen/main_addrimport.py | 1 + mmgen/main_tool.py | 1 + mmgen/main_txcreate.py | 3 +- mmgen/main_txsend.py | 1 + mmgen/main_txsign.py | 1 + mmgen/opts.py | 4 +- mmgen/rpc.py | 1 + mmgen/share/Opts.py | 32 +++++++++----- mmgen/tw.py | 2 +- scripts/bitcoind-walletunlock.py | 41 +++++------------ scripts/compute-file-chksum.py | 4 +- scripts/deinstall.sh | 10 +++-- setup.py | 5 ++- test/gentest.py | 3 +- test/test.py | 75 +++++++++++++++++--------------- test/tooltest.py | 2 + 19 files changed, 115 insertions(+), 96 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index acfaf349..bd854779 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,10 @@ include README.md SIGNING_KEY.pub LICENSE INSTALL include doc/wiki/using-mmgen/* include test/*.py include test/ref/* + +include scripts/bitcoind-walletunlock.py +include scripts/compute-file-chksum.py +include scripts/deinstall.sh +include scripts/tx-old2new.py + prune test/ref/__db* diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index ff6af3ef..f17edf93 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -20,6 +20,9 @@ globalvars.py: Constants and configuration options for the MMGen suite """ +version = '0.8.7a' +release_date = 'November 2016' + import sys,os # Variables - these might be altered at runtime: @@ -53,12 +56,11 @@ prog_name = os.path.basename(sys.argv[0]) author = 'Philemon' email = '' Cdates = '2013-2016' -version = '0.8.7' required_opts = [ - 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file', - 'usr_randchars','stdout','show_hash_presets','label', - 'keep_passphrase','keep_hash_preset','brain_params','b16' + 'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout', + 'show_hash_presets','label','keep_passphrase','keep_hash_preset', + 'brain_params','b16','usr_randchars' ] incompatible_opts = ( ('quiet','verbose'), @@ -71,9 +73,13 @@ incompatible_opts = ( min_screen_width = 80 minconf = 1 -# Global value sets user opt +# Global var sets user opt: dfl_vars = 'minconf','seed_len','hash_preset','usr_randchars','debug','tx_confs','tx_fee_adj','tx_fee','key_generator' +# User opt sets global var: +usr_sets_global = ['testnet'] +required_opts += usr_sets_global + keyconv_exec = 'keyconv' mins_per_block = 9 diff --git a/mmgen/main_addrgen.py b/mmgen/main_addrgen.py index b3d81655..e7ff062b 100755 --- a/mmgen/main_addrgen.py +++ b/mmgen/main_addrgen.py @@ -34,7 +34,7 @@ By default, both addresses and secret keys are generated. """.strip() else: gen_what = 'addresses' - opt_filter = 'hbcdeiHOKlpzPqSv' + opt_filter = 'hbcdeiHOKlpzPqSv-' note1 = """ If available, the external 'keyconv' program will be used for address generation. @@ -66,6 +66,7 @@ opts_data = { -P, --passwd-file= f Get wallet passphrase from file 'f'. -q, --quiet Produce quieter output; suppress some warnings. -S, --stdout Print {what} to stdout. +--, --testnet Generate testnet keys/addresses instead of mainnet ones -v, --verbose Produce more verbose output. -x, --b16 Print secret keys in hexadecimal too. """.format( diff --git a/mmgen/main_addrimport.py b/mmgen/main_addrimport.py index d12ad86f..392de726 100755 --- a/mmgen/main_addrimport.py +++ b/mmgen/main_addrimport.py @@ -41,6 +41,7 @@ opts_data = { -r, --rescan Rescan the blockchain. Required if address to import is on the blockchain and has a balance. Rescanning is slow. -t, --test Simulate operation; don't actually import addresses +--, --testnet Use Bitcoin testnet instead of mainnet """, 'notes': """\n This command can also be used to update the comment fields of addresses already diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index a900bcdf..f865c9f4 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -34,6 +34,7 @@ opts_data = { -q, --quiet Produce quieter output -r, --usr-randchars=n Get 'n' characters of additional randomness from user (min={g.min_urandchars}, max={g.max_urandchars}) +--, --testnet Use Bitcoin testnet instead of mainnet -v, --verbose Produce more verbose output """.format(g=g), 'notes': """ diff --git a/mmgen/main_txcreate.py b/mmgen/main_txcreate.py index f4f09899..5c2d2b93 100755 --- a/mmgen/main_txcreate.py +++ b/mmgen/main_txcreate.py @@ -33,14 +33,15 @@ opts_data = { 'options': """ -h, --help Print this help message -a, --tx-fee-adj= f Adjust transaction fee by factor 'f' (see below) +-B, --no-blank Don't blank screen before displaying unspent outputs -c, --comment-file= f Source the transaction's comment from file 'f' -C, --tx-confs= c Desired number of confirmations (default: {g.tx_confs}) -d, --outdir= d Specify an alternate directory 'd' for output --e, --clear-screen Clear screen before displaying unspent outputs -f, --tx-fee= f Transaction fee (default: {g.tx_fee} BTC (but see below)) -m, --minconf= n Minimum number of confirmations required to spend outputs (default: 1) -i, --info Display unspent outputs and exit -q, --quiet Suppress warnings; overwrite files without prompting +--, --testnet Create transaction for Bitcoin testnet instead of mainnet -v, --verbose Produce more verbose output """.format(g=g), 'notes': """ diff --git a/mmgen/main_txsend.py b/mmgen/main_txsend.py index f8f805f7..a42074c7 100755 --- a/mmgen/main_txsend.py +++ b/mmgen/main_txsend.py @@ -31,6 +31,7 @@ opts_data = { -h, --help Print this help message -d, --outdir= d Specify an alternate directory 'd' for output -q, --quiet Suppress warnings; overwrite files without prompting +--, --testnet Use Bitcoin testnet instead of mainnet """ } diff --git a/mmgen/main_txsign.py b/mmgen/main_txsign.py index 8911a80e..a310f7d1 100755 --- a/mmgen/main_txsign.py +++ b/mmgen/main_txsign.py @@ -63,6 +63,7 @@ opts_data = { prompting -I, --info Display information about the transaction and exit. -t, --terse-info Like '--info', but produce more concise output. +--, --testnet Transaction is for Bitcoin testnet rather than mainnet -v, --verbose Produce more verbose output """.format( g=g,pnm=pnm,pnl=pnm.lower(), diff --git a/mmgen/opts.py b/mmgen/opts.py index 83d1b024..0492f75d 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -130,8 +130,10 @@ def init(opts_data,add_opts=[],opt_filter=None): g.required_opts + add_opts + skipped_opts: setattr(opt,o,uopts[o] if o in uopts else None) - # A special case - do this here, before opt gets set from g.dfl_vars + # User opt sets global var - do these here, before opt gets set from g.dfl_vars if opt.usr_randchars: g.use_urandchars = True + for k in g.usr_sets_global: + if getattr(opt,k): setattr(g,k,True) # If user opt is set, convert its type based on value in mmgen.globalvars (g) # If unset, set it to default value in mmgen.globalvars (g) diff --git a/mmgen/rpc.py b/mmgen/rpc.py index 61f008ff..a1a720b7 100755 --- a/mmgen/rpc.py +++ b/mmgen/rpc.py @@ -152,6 +152,7 @@ class BitcoinRPCConnection(object): 'sendrawtransaction', 'signrawtransaction', 'getrawmempool', + 'walletpassphrase', ) for name in rpcmethods: diff --git a/mmgen/share/Opts.py b/mmgen/share/Opts.py index 62b5697b..fe569ea2 100755 --- a/mmgen/share/Opts.py +++ b/mmgen/share/Opts.py @@ -21,6 +21,7 @@ Opts.py: Generic options handling """ import sys, getopt +from mmgen.util import pp_die,pp_msg # DEBUG def usage(opts_data): print 'USAGE: %s %s' % (opts_data['prog_name'], opts_data['usage']) @@ -43,26 +44,27 @@ def process_opts(argv,opts_data,short_opts,long_opts): opts_data['prog_name'] = os.path.basename(sys.argv[0]) long_opts = [i.replace('_','-') for i in long_opts] - try: cl_opts,args = getopt.getopt(argv[1:], short_opts, long_opts) +# pp_msg(long_opts) # DEBUG + try: cl_opts,args = getopt.getopt(argv[1:], short_opts.replace('-',''), long_opts) except getopt.GetoptError as err: print str(err); sys.exit(2) - opts,short_opts_l = {},[] - - for i in short_opts: - if i == ':': short_opts_l[-1] += i - else: short_opts_l += i + sopts_list = ':_'.join(['_'.join(list(i)) for i in short_opts.split(':')]).split('_') + opts = {} +# pp_msg(cl_opts) # DEBUG +# pp_msg(sopts_list) # DEBUG +# pp_die(args) for opt, arg in cl_opts: if opt in ('-h','--help'): print_help(opts_data); sys.exit() elif opt[:2] == '--' and opt[2:] in long_opts: opts[opt[2:].replace('-','_')] = True elif opt[:2] == '--' and opt[2:]+'=' in long_opts: opts[opt[2:].replace('-','_')] = arg - elif opt[0] == '-' and opt[1] in short_opts_l: - opts[long_opts[short_opts_l.index(opt[1:])].replace('-','_')] = True - elif opt[0] == '-' and opt[1:]+':' in short_opts_l: - opts[long_opts[short_opts_l.index( + elif opt[1] != '-' and opt[1] in sopts_list: + opts[long_opts[sopts_list.index(opt[1:])].replace('-','_')] = True + elif opt[1] != '-' and opt[1:]+':' in sopts_list: + opts[long_opts[sopts_list.index( opt[1:]+':')][:-1].replace('-','_')] = arg else: assert False, 'Invalid option' @@ -87,7 +89,7 @@ def process_opts(argv,opts_data,short_opts,long_opts): def parse_opts(argv,opts_data,opt_filter=None): import re - pat = r'^-([a-zA-Z0-9]), --([a-zA-Z0-9-]{2,64})(=| )(.+)' + pat = r'^-([a-zA-Z0-9-]), --([a-zA-Z0-9-]{2,64})(=| )(.+)' od,skip = [],True for l in opts_data['options'].strip().splitlines(): @@ -100,12 +102,18 @@ def parse_opts(argv,opts_data,opt_filter=None): if not skip: od[-1][3] += '\n' + l opts_data['options'] = '\n'.join( - ['-{}, --{} {}'.format(d[0],d[1],d[3]) for d in od if d[6] == False] + ['{:<3} --{} {}'.format( + ('-'+d[0]+',','')[d[0]=='-'],d[1],d[3]) for d in od if d[6] == False] ) +# print opts_data['options']; sys.exit() # DEBUG +# pp_die(od) # DEBUG short_opts = ''.join([d[0]+d[4] for d in od if d[6] == False]) long_opts = [d[1].replace('-','_')+d[5] for d in od if d[6] == False] skipped_opts = [d[1].replace('-','_') for d in od if d[6] == True] +# pp_die(short_opts) # DEBUG +# pp_msg(long_opts) # DEBUG opts,args = process_opts(argv,opts_data,short_opts,long_opts) +# pp_die(opts) # DEBUG return opts,args,short_opts,long_opts,skipped_opts diff --git a/mmgen/tw.py b/mmgen/tw.py index 1fa10ed1..50aa50f5 100755 --- a/mmgen/tw.py +++ b/mmgen/tw.py @@ -123,7 +123,7 @@ watch-only wallet using '{}-addrimport' and then re-run this program. my_raw_input(m1+'\n'+m2.format(g.min_screen_width)) def display(self): - if opt.clear_screen: msg(CUR_HOME+ERASE_ALL) + if not opt.no_blank: msg(CUR_HOME+ERASE_ALL) msg(self.format_for_display()) def format_for_display(self): diff --git a/scripts/bitcoind-walletunlock.py b/scripts/bitcoind-walletunlock.py index c1641a36..591079e4 100755 --- a/scripts/bitcoind-walletunlock.py +++ b/scripts/bitcoind-walletunlock.py @@ -19,43 +19,22 @@ bitcoind-walletunlock.py: Unlock a Bitcoin wallet securely """ -import sys -from mmgen.Opts import * -from mmgen.tx import * -from mmgen.util import msg, my_getpass, my_raw_input +import sys,getpass +from mmgen.common import * -prog_name = sys.argv[0].split("/")[-1] - -help_data = { - 'prog_name': prog_name, +opts_data = { + 'prog_name': sys.argv[0].split('/')[-1], 'desc': "Unlock a Bitcoin wallet securely", 'usage': "[opts]", 'options': """ --h, --help Print this help message --e, --echo-passphrase Print passphrase to screen when typing it +-h, --help Print this help message +-e, --echo-passphrase Print passphrase to screen when typing it +--, --testnet Use testnet instead of mainnet """ } -short_opts = "he" -long_opts = "help","echo_passphrase" +cmd_args = opts.init(opts_data) -opts,cmd_args = process_opts(sys.argv,help_data,short_opts,long_opts) +password = (getpass.getpass,raw_input)[bool(opt.echo_passphrase)]('Enter passphrase: ') -c = connect_to_bitcoind() - -prompt = "Enter passphrase: " -if 'echo_passphrase' in opts: - password = my_raw_input(prompt) -else: - password = my_getpass(prompt) - -from bitcoinrpc import exceptions - -try: - c.walletpassphrase(password, 9999) -except exceptions.WalletWrongEncState: - msg("Wallet is unencrypted") -except exceptions.WalletPassphraseIncorrect: - msg("Passphrase incorrect") -except exceptions.WalletAlreadyUnlocked: - msg("WARNING: Wallet already unlocked!") +bitcoin_connection().walletpassphrase(password, 9999); msg('OK') diff --git a/scripts/compute-file-chksum.py b/scripts/compute-file-chksum.py index 9c7485aa..4a6c293c 100755 --- a/scripts/compute-file-chksum.py +++ b/scripts/compute-file-chksum.py @@ -1,7 +1,6 @@ #!/usr/bin/env python from mmgen.common import * -from mmgen.util import * opts_data = { 'desc': 'Compute checksum for a MMGen data file', @@ -19,5 +18,6 @@ start = (1,0)[bool(opt.include_first_line)] a = make_chksum_6(' '.join(lines[start:])) if start == 1: b = lines[0] - msg(("Checksum in file (%s) doesn't match computed value!" % b,"Checksum in file OK")[a==b]) + m = ("Checksum in file (%s) doesn't match computed value!" % b,'Checksum in file OK')[a==b] + msg(m) Msg(a) diff --git a/scripts/deinstall.sh b/scripts/deinstall.sh index 88ee8a15..00d95389 100755 --- a/scripts/deinstall.sh +++ b/scripts/deinstall.sh @@ -1,7 +1,9 @@ #!/bin/bash -CMD='rm -r /usr/local/bin/mmgen-* /usr/local/lib/python2.7/dist-packages/mmgen*' +CMD='rm -rf /usr/local/bin/mmgen-* /usr/local/lib/python2.7/dist-packages/mmgen*' -set -x - -if [ "$EUID" = 0 ]; then $CMD; else sudo $CMD; fi +if [ "$EUID" = 0 ]; then + set -x; $CMD +else + set -x; sudo $CMD +fi diff --git a/setup.py b/setup.py index 268e9c28..a41de442 100755 --- a/setup.py +++ b/setup.py @@ -42,10 +42,11 @@ module1 = Extension( include_dirs = ['/usr/local/include'], ) +from mmgen.globalvars import version setup( name = 'mmgen', description = 'A complete Bitcoin offline/online wallet solution for the command line', - version = '0.8.7', + version = version, author = 'Philemon', author_email = 'mmgen-py@yandex.com', url = 'https://github.com/mmgen/mmgen', @@ -100,6 +101,6 @@ setup( 'mmgen-txcreate', 'mmgen-txsign', 'mmgen-txsend', - 'mmgen-tool', + 'mmgen-tool' ] ) diff --git a/test/gentest.py b/test/gentest.py index c5d4b0d1..bc8441c6 100755 --- a/test/gentest.py +++ b/test/gentest.py @@ -39,8 +39,9 @@ opts_data = { 'usage':'[options] [spec] [rounds | dump file]', 'options': """ -h, --help Print this help message --v, --verbose Produce more verbose output -q, --quiet Produce quieter output +--, --testnet Run for testnet rather than mainnet +-v, --verbose Produce more verbose output """, 'notes': """ Tests: diff --git a/test/test.py b/test/test.py index 17e943f3..f0d3cf41 100755 --- a/test/test.py +++ b/test/test.py @@ -45,6 +45,45 @@ sys.path.__setitem__(0,os.path.abspath(os.curdir)) # Import these _after_ local path's been added to sys.path from mmgen.common import * from mmgen.test import * + +tb_cmd = 'scripts/traceback.py' +log_file = 'test.py_log' + +opts_data = { +# 'sets': [('non_interactive',bool,'verbose',None)], + 'desc': 'Test suite for the MMGen suite', + 'usage':'[options] [command(s) or metacommand(s)]', + 'options': """ +-h, --help Print this help message. +-b, --buf-keypress Use buffered keypresses as with real human input. +-d, --debug-scripts Turn on debugging output in executed scripts. +-D, --direct-exec Bypass pexpect and execute a command directly (for + debugging only). +-e, --exact-output Show the exact output of the MMGen script(s) being run. +-l, --list-cmds List and describe the commands in the test suite. +-L, --log Log commands to file {lf} +-n, --names Display command names instead of descriptions. +-I, --non-interactive Non-interactive operation (MS Windows mode) +-p, --pause Pause between tests, resuming on keypress. +-P, --profile Record the execution time of each script. +-q, --quiet Produce minimal output. Suppress dependency info. +-r, --resume=c Resume at command 'c' after interrupted run +-s, --system Test scripts and modules installed on system rather + than those in the repo root. +-S, --skip-deps Skip dependency checking for command +-u, --usr-random Get random data interactively from user +--, --testnet Run on testnet rather than mainnet +-t, --traceback Run the command inside the '{tb_cmd}' script. +-v, --verbose Produce more verbose output. +""".format(tb_cmd=tb_cmd,lf=log_file), + 'notes': """ + +If no command is given, the whole suite of tests is run. +""" +} + +cmd_args = opts.init(opts_data) + tn_desc = ('','.testnet')[g.testnet] start_mscolor() @@ -56,7 +95,6 @@ scripts = ( 'walletchk', 'walletconv', 'walletgen' ) -tb_cmd = 'scripts/traceback.py' hincog_fn = 'rand_data' hincog_bytes = 1024*1024 hincog_offset = 98765 @@ -466,41 +504,8 @@ meta_cmds = OrderedDict([ ]) del cmd_group -log_file = 'test.py_log' -opts_data = { -# 'sets': [('non_interactive',bool,'verbose',None)], - 'desc': 'Test suite for the MMGen suite', - 'usage':'[options] [command(s) or metacommand(s)]', - 'options': """ --h, --help Print this help message. --b, --buf-keypress Use buffered keypresses as with real human input. --d, --debug-scripts Turn on debugging output in executed scripts. --D, --direct-exec Bypass pexpect and execute a command directly (for - debugging only). --e, --exact-output Show the exact output of the MMGen script(s) being run. --l, --list-cmds List and describe the commands in the test suite. --L, --log Log commands to file {lf} --n, --names Display command names instead of descriptions. --I, --non-interactive Non-interactive operation (MS Windows mode) --p, --pause Pause between tests, resuming on keypress. --P, --profile Record the execution time of each script. --q, --quiet Produce minimal output. Suppress dependency info. --r, --resume=c Resume at command 'c' after interrupted run --s, --system Test scripts and modules installed on system rather - than those in the repo root. --S, --skip-deps Skip dependency checking for command --u, --usr-random Get random data interactively from user --t, --traceback Run the command inside the '{tb_cmd}' script. --v, --verbose Produce more verbose output. -""".format(tb_cmd=tb_cmd,lf=log_file), - 'notes': """ - -If no command is given, the whole suite of tests is run. -""" -} - -cmd_args = opts.init(opts_data) +if opt.testnet: os.environ['MMGEN_TESTNET'] = '1' if opt.profile: opt.names = True if opt.resume: opt.skip_deps = True diff --git a/test/tooltest.py b/test/tooltest.py index 5603f790..0aa681fd 100755 --- a/test/tooltest.py +++ b/test/tooltest.py @@ -116,6 +116,7 @@ opts_data = { -l, --list-cmds List and describe the tests and commands in the test suite -s, --system Test scripts and modules installed on system rather than those in the repo root +--, --testnet Run on testnet rather than mainnet -v, --verbose Produce more verbose output """, 'notes': """ @@ -125,6 +126,7 @@ If no command is given, the whole suite of tests is run. } cmd_args = opts.init(opts_data,add_opts=['exact_output','profile']) +if opt.testnet: os.environ['MMGEN_TESTNET'] = '1' if opt.system: sys.path.pop(0)