diff --git a/mmgen/exception.py b/mmgen/exception.py index f6c5304f..fba19108 100755 --- a/mmgen/exception.py +++ b/mmgen/exception.py @@ -22,6 +22,8 @@ mmgen.exception: Exception classes for the MMGen suite # 1: no hl, message only class UserNonConfirmation(Exception): mmcode = 1 +class BadAgeFormat(Exception): mmcode = 1 +class BadFilename(Exception): mmcode = 1 # 2: yellow hl, message only class UnrecognizedTokenSymbol(Exception): mmcode = 2 diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 11b0dbf4..5c41d287 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -50,7 +50,7 @@ class g(object): keywords = 'Bitcoin, BTC, cryptocurrency, wallet, cold storage, offline, online, spending, open-source, command-line, Python, Linux, Bitcoin Core, bitcoind, hd, deterministic, hierarchical, secure, anonymous, Electrum, seed, mnemonic, brainwallet, Scrypt, utility, script, scriptable, blockchain, raw, transaction, permissionless, console, terminal, curses, ansi, color, tmux, remote, client, daemon, RPC, json, entropy, xterm, rxvt, PowerShell, MSYS, MinGW, mswin, Armbian, Raspbian, Raspberry Pi, Orange Pi, BCash, BCH, Litecoin, LTC, altcoin, ZEC, Zcash, DASH, Dashpay, ETH, Ethereum, Classic, SHA256Compress, XMR, Monero, monerod, EMC, Emercoin, ERC20, token, deploy, contract, gas, fee, smart contract, solidity, Parity, testnet, devmode, Kovan' max_int = 0xffffffff - stdin_tty = bool(sys.stdin.isatty() or os.getenv('MMGEN_TEST_SUITE')) + stdin_tty = bool(sys.stdin.isatty() or os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN')) stdout_fileno = sys.stdout.fileno() stderr_fileno = sys.stderr.fileno() diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 4116ab27..db824d7c 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -23,96 +23,35 @@ mmgen-tool: Perform various MMGen- and cryptocoin-related operations. from mmgen.common import * -stdin_msg = """ -To force a command to read from STDIN in place of its first argument (for -supported commands), use '-' as the first argument. -""".strip() +def make_cmd_help(): + import mmgen.tool + out = [] + for bc in mmgen.tool.MMGenToolCmd.__bases__: + cls_doc = bc.__doc__.strip().split('\n') + for l in cls_doc: + if l is cls_doc[0]: l += ':' + l = l.replace('\t','',1) + if l: + l = l.replace('\t',' ') + out.append(l[0].upper() + l[1:]) + else: + out.append('') + out.append('') -cmd_help = """ -Cryptocoin address/key operations (compressed public keys supported): - addr2hexaddr - convert coin address from base58 to hex format - hex2wif - convert a private key from hex to WIF format (use '--type=zcash_z' for zcash-z key) - pubhash2addr - convert public key hash to address - privhex2addr - generate coin address from private key in hex format - privhex2pubhex - generate a hex public key from a hex private key - pubhex2addr - convert a hex pubkey to an address - pubhex2redeem_script - convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script - wif2redeem_script - convert a WIF private key to a Segwit P2SH-P2WPKH redeem script - wif2segwit_pair - generate both a Segwit P2SH-P2WPKH redeem script and address from WIF - pubkey2addr - convert coin public key to address - randpair - generate a random private key/address pair - randwif - generate a random private key in WIF format - wif2addr - generate a coin address from a key in WIF format - wif2hex - convert a private key from WIF to hex format + cls_funcs = bc.user_commands() + max_w = max(map(len,cls_funcs)) + fs = ' {{:{}}} - {{}}'.format(max_w) + for func in cls_funcs: + m = getattr(bc,func) + if m.__doc__: + out.append(fs.format(func, + pretty_format( m.__doc__.strip().replace('\n\t\t',' '), + width=79-(max_w+7), + pfx=' '*(max_w+5)).lstrip() + )) + out.append('') -Wallet/TX operations (coin daemon must be running): - gen_addr - generate a single MMGen address from default or specified wallet - gen_key - generate a single MMGen WIF key from default or specified wallet - getbalance - like '{pn}-cli getbalance' but shows confirmed/unconfirmed, - spendable/unspendable balances for individual {pnm} wallets - listaddress - list the specified {pnm} address and its balance - listaddresses - list {pnm} addresses and their balances - txview - show raw/signed {pnm} transaction in human-readable form - twview - view tracking wallet - - keyaddrlist2monerowallets - create Monero wallets from key-address list - syncmonerowallets - sync Monero wallets from key-address list - -General utilities: - hexdump - encode data into formatted hexadecimal form (file or stdin) - unhexdump - decode formatted hexadecimal data (file or stdin) - bytespec - convert a byte specifier such as '1GB' into an integer - hexlify - display string in hexadecimal format - hexreverse - reverse bytes of a hexadecimal string - rand2file - write 'n' bytes of random data to specified file - randhex - print 'n' bytes (default 32) of random data in hex format - hash256 - compute sha256(sha256(data)) (double sha256) - hash160 - compute ripemd160(sha256(data)) (converts hexpubkey to hexaddr) - b58randenc - generate a random 32-byte number and convert it to base 58 - b58tostr - convert a base 58 number to a string - strtob58 - convert a string to base 58 - b58tohex - convert a base 58 number to hexadecimal - b58chktohex - convert a base58-check encoded number to hexadecimal - hextob58 - convert a hexadecimal number to base 58 - hextob58chk - convert a hexadecimal number to base58-check encoding - b32tohex - convert a base 32 number to hexadecimal - hextob32 - convert a hexadecimal number to base 32 - -File encryption: - encrypt - encrypt a file - decrypt - decrypt a file - {pnm} encryption suite: - * Key: Scrypt (user-configurable hash parameters, 32-byte salt) - * Enc: AES256_CTR, 16-byte rand IV, sha256 hash + 32-byte nonce + data - * The encrypted file is indistinguishable from random data - -{pnm}-specific operations: - remove_address - remove an address from tracking wallet - add_label - add descriptive label for {pnm} address in tracking wallet - remove_label - remove descriptive label for {pnm} address in tracking wallet - addrfile_chksum - compute checksum for {pnm} address file - keyaddrfile_chksum - compute checksum for {pnm} key-address file - passwdfile_chksum - compute checksum for {pnm} password file - find_incog_data - Use an Incog ID to find hidden incognito wallet data - id6 - generate 6-character {pnm} ID for a file (or stdin) - id8 - generate 8-character {pnm} ID for a file (or stdin) - str2id6 - generate 6-character {pnm} ID for a string, ignoring spaces - -Mnemonic operations (choose 'electrum' (default), 'tirosh' or 'all' - wordlists): - mn_rand128 - generate random 128-bit mnemonic - mn_rand192 - generate random 192-bit mnemonic - mn_rand256 - generate random 256-bit mnemonic - mn_stats - show stats for mnemonic wordlist - mn_printlist - print mnemonic wordlist - hex2mn - convert a 16, 24 or 32-byte number in hex format to a mnemonic - mn2hex - convert a 12, 18 or 24-word mnemonic to a number in hex format - - IMPORTANT NOTE: Though {pnm} mnemonics use the Electrum wordlist, they're - computed using a different algorithm and are NOT Electrum-compatible! - - {sm} -""" + return '\n'.join(out) opts_data = lambda: { 'desc': 'Perform various {pnm}- and cryptocoin-related operations'.format(pnm=g.proj_name), @@ -125,20 +64,17 @@ opts_data = lambda: { -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}) --t, --type=t Specify address type (valid options: 'compressed','segwit','bech32','zcash_z') +-t, --type=t Specify address type (valid options: 'legacy', + 'compressed', 'segwit', 'bech32', 'zcash_z') -v, --verbose Produce more verbose output """.format(g=g), 'notes': """ COMMANDS + {ch} -Type '{pn} help for help on a particular command -""".format( pn=g.prog_name, - ch=cmd_help.format( - pn=g.proto.name, - pnm=g.proj_name, - sm='\n '.join(stdin_msg.split('\n'))) - ) +Type '{pn} help ' for help on a particular command +""".format(pn=g.prog_name,ch=make_cmd_help()) } cmd_args = opts.init(opts_data,add_opts=['hidden_incog_input_params','in_fmt','use_old_ed25519']) @@ -149,8 +85,9 @@ cmd = cmd_args.pop(0) import mmgen.tool as tool tc = tool.MMGenToolCmd() -if cmd == 'help' and not cmd_args: - tool._usage(exit_val=0) +if cmd in ('help','usage') and cmd_args: + cmd_args[0] = 'command_name=' + cmd_args[0] + if cmd not in dir(tc): die(1,"'{}': no such command".format(cmd)) @@ -158,4 +95,4 @@ args,kwargs = tool._process_args(cmd,cmd_args) ret = getattr(tc,cmd)(*args,**kwargs) -tool._print_result(ret,'pager' in kwargs and kwargs['pager']) +tool._process_result(ret,to_screen=True,pager='pager' in kwargs and kwargs['pager']) diff --git a/mmgen/tool.py b/mmgen/tool.py index b3154dc2..b31e1a11 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -17,172 +17,127 @@ # along with this program. If not, see . """ -tool.py: Routines and data for the 'mmgen-tool' utility +tool.py: Routines for the 'mmgen-tool' utility """ -import binascii -from collections import OrderedDict +from binascii import hexlify,unhexlify from mmgen.protocol import hash160 from mmgen.common import * from mmgen.crypto import * -from mmgen.tx import * from mmgen.addr import * -pnm = g.proj_name -cmd_data = OrderedDict([ - ('help', [' [str]']), - ('usage', [' [str]']), - ('strtob58', [' [str-]','pad [int=0]']), - ('b58tostr', [' [str-]']), - ('hextob58', [' [str-]','pad [int=0]']), - ('hextob58chk', [' [str-]']), - ('b58tohex', [' [str-]','pad [int=0]']), - ('b58chktohex', [' [str-]']), - ('b58randenc', []), - ('b32tohex', [' [str-]','pad [int=0]']), - ('hextob32', [' [str-]','pad [int=0]']), - ('randhex', ['nbytes [int=32]']), - ('id8', [' [str]']), - ('id6', [' [str]']), - ('hash160', [' [str-]']), - ('hash256', [' [str]', # TODO handle stdin - 'hex_input [bool=False]','file_input [bool=False]']), - ('str2id6', [' [str-]']), - ('hexdump', [' [str]', 'cols [int=8]', 'line_nums [bool=True]']), - ('unhexdump', [' [str]']), - ('hexreverse', [' [str-]']), - ('hexlify', [' [str-]']), - ('rand2file', [' [str]',' [str]','threads [int=4]','silent [bool=False]']), +def _create_call_sig(cmd,parsed=False): - ('randwif', []), - ('randpair', []), - ('hex2wif', [' [str-]']), - ('wif2hex', [' [str-]']), - ('wif2addr', [' [str-]']), - ('wif2segwit_pair',[' [str-]']), - ('pubhash2addr', [' [str-]']), - ('addr2hexaddr', [' [str-]']), - ('privhex2addr', [' [str-]']), - ('privhex2pubhex',[' [str-]']), - ('pubhex2addr', [' [str-]']), # new - ('pubhex2redeem_script',[' [str-]']), # new - ('wif2redeem_script', [' [str-]']), # new + m = getattr(MMGenToolCmd,cmd) - ('hex2mn', [' [str-]',"wordlist [str='electrum']"]), - ('mn2hex', [' [str-]', "wordlist [str='electrum']"]), - ('mn_rand128', ["wordlist [str='electrum']"]), - ('mn_rand192', ["wordlist [str='electrum']"]), - ('mn_rand256', ["wordlist [str='electrum']"]), - ('mn_stats', ["wordlist [str='electrum']"]), - ('mn_printlist', ["wordlist [str='electrum']"]), + if 'varargs_call_sig' in m.__code__.co_varnames: # hack + flag = 'VAR_ARGS' + va = m.__defaults__[0] + args,dfls,ann = va['args'],va['dfls'],va['annots'] + else: + flag = None + args = m.__code__.co_varnames[1:m.__code__.co_argcount] + dfls = m.__defaults__ or () + ann = m.__annotations__ - ('gen_addr', ['<{} ID> [str]'.format(pnm),"wallet [str='']"]), - ('gen_key', ['<{} ID> [str]'.format(pnm),"wallet [str='']"]), + nargs = len(args) - len(dfls) - ('listaddress',['<{} address> [str]'.format(pnm),'minconf [int=1]','pager [bool=False]','showempty [bool=True]','showbtcaddr [bool=True]','show_age [bool=False]','show_days [bool=True]']), - ('listaddresses',["addrs [str='']",'minconf [int=1]','showempty [bool=False]','pager [bool=False]','showbtcaddrs [bool=True]','all_labels [bool=False]',"sort [str=''] (options: reverse, age)",'show_age [bool=False]','show_days [bool=True]']), - ('getbalance', ['minconf [int=1]','quiet [bool=False]','pager [bool=False]']), - ('txview', ['<{} TX file(s)> [str]'.format(pnm),'pager [bool=False]','terse [bool=False]',"sort [str='mtime'] (options: ctime, atime)",'MARGS']), - ('twview', ["sort [str='age']",'reverse [bool=False]','show_days [bool=True]','show_mmid [bool=True]','minconf [int=1]','wide [bool=False]','pager [bool=False]']), - - ('add_label', ['<{} or coin address> [str]'.format(pnm),'