From f80566304195bd2318a9213c61ea1f4b9259eb75 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 15 Feb 2020 14:32:14 +0000 Subject: [PATCH] new Tool API interface - provides a convenient interface to selected methods in the mmgen.tool module - Type `pydoc3 mmgen.tool.tool_api` for available methods and call signatures ## Examples: ### Initialize: from mmgen.tool import tool_api tool = tool_api() ### Utility methods: # Skip user entropy gathering (not recommended) tool.usr_randchars = 0 # Generate a random hex secret: hexsec = tool.randhex() # Reverse the hex string: hexsec_rev = tool.hexreverse(hexsec) # Get the HASH160 of the value: sec_hash160 = tool.hash160(hexsec) # Convert the value to base58 format: sec_b58 = tool.hextob58(hexsec) # Convert the value to base58 check format: sec_b58chk = tool.hextob58chk(hexsec) # Convert the byte specification '4G' to an integer: four_g = tool.bytespec('4G') # Convert the byte specification '4GB' to an integer: four_gb = tool.bytespec('4GB') ### Key/address generation: # List available coins: print(' '.join(tool.coins)) # Initialize a coin/network pair: proto = tool.init_coin('btc','mainnet') # Print the available address types for current coin/network, along with a # description. If tool.addrtype is unset, the first-listed will be used: tool.print_addrtypes() # Set the address type to P2PKH with compressed public key: tool.addrtype = 'compressed' # Generate the key and address: wif = tool.hex2wif(hexsec) addr = tool.wif2addr(wif) # Generate an LTC regtest Segwit key and address: proto = tool.init_coin('ltc','regtest') tool.addrtype = 'segwit' wif = tool.hex2wif(hexsec) addr = tool.wif2addr(wif) # Generate a random LTC regtest Bech32 key/address pair: tool.addrtype = 'bech32' wif,addr = tool.randpair() ### Mnemonic seed phrase generation: # Generate an MMGen native mnemonic seed phrase: mmgen_seed = tool.hex2mn(hexsec) # Generate a BIP39 mnemonic seed phrase: bip39_seed = tool.hex2mn(hexsec,fmt='bip39') --- mmgen/tool.py | 113 ++++++++++++++++++++++++++++++++++++++++++++++ test/tooltest2.py | 28 +++++++++++- 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/mmgen/tool.py b/mmgen/tool.py index c6b7b548..eb9a043e 100755 --- a/mmgen/tool.py +++ b/mmgen/tool.py @@ -1087,3 +1087,116 @@ class MMGenToolCmd( MMGenToolCmdRPC, MMGenToolCmdMonero, ): pass + +class tool_api( + MMGenToolCmdUtil, + MMGenToolCmdCoin, + MMGenToolCmdMnemonic, + ): + """ + API providing access to a subset of methods from the mmgen.tool module + + Example: + from mmgen.tool import tool_api + tool = tool_api() + + # Set the coin and network: + tool.init_coin('btc','mainnet') + + # Print available address types: + tool.print_addrtypes() + + # Set the address type: + tool.addrtype = 'segwit' + + # Disable user entropy gathering (optional, reduces security): + tool.usr_randchars = 0 + + # Generate a random BTC segwit keypair: + wif,addr = tool.randpair() + + # Set coin, network and address type: + tool.init_coin('ltc','testnet') + tool.addrtype = 'bech32' + + # Generate a random LTC testnet Bech32 keypair: + wif,addr = tool.randpair() + """ + + def __init__(self): + """ + Initializer - takes no arguments + """ + if not hasattr(opt,'version'): + opts.init({'text': { 'desc': '', 'usage':'', 'options':'' }}) + opt.use_old_ed25519 = None + opt.type = None + + def init_coin(self,coinsym,network): + """ + Initialize a coin/network pair + Valid choices for coins: one of the symbols returned by the 'coins' attribute + Valid choices for network: 'mainnet','testnet','regtest' + """ + from mmgen.protocol import init_coin,init_genonly_altcoins + init_genonly_altcoins(coinsym) + if network == 'regtest': + g.regtest = True + return init_coin(coinsym,{'mainnet':False,'testnet':True,'regtest':True}[network]) + + @property + def coins(self): + """The available coins""" + from mmgen.protocol import CoinProtocol + from mmgen.altcoin import CoinInfo + return sorted(set(CoinProtocol.list_coins() + [c.symbol for c in CoinInfo.get_supported_coins(g.network)])) + + @property + def coin(self): + """The currently configured coin""" + return g.coin + + @property + def network(self): + """The currently configured network""" + if g.network == 'testnet': + return ('testnet','regtest')[g.regtest] + else: + return g.network + + @property + def addrtypes(self): + """ + The available address types for current coin/network pair. The + first-listed is the default + """ + return [MMGenAddrType(t).name for t in g.proto.mmtypes] + + def print_addrtypes(self): + """ + Print the available address types for current coin/network pair along with + a description. The first-listed is the default + """ + for t in [MMGenAddrType(s) for s in g.proto.mmtypes]: + print('{:<12} - {}'.format(t.name,t.desc)) + + @property + def addrtype(self): + """The currently configured address type (is assignable)""" + return opt.type + + @addrtype.setter + def addrtype(self,val): + opt.type = val + + @property + def usr_randchars(self): + """ + The number of keystrokes of entropy to be gathered from the user. + Setting to zero disables user entropy gathering. + """ + return opt.usr_randchars + + @usr_randchars.setter + def usr_randchars(self,val): + opt.usr_randchars = val diff --git a/test/tooltest2.py b/test/tooltest2.py index 4a8b3d22..c88c7e3c 100755 --- a/test/tooltest2.py +++ b/test/tooltest2.py @@ -55,6 +55,7 @@ opts_data = { 'usage':'[options] [command]...', 'options': """ -h, --help Print this help message +-A, --tool-api Test the tool_api subsystem -C, --coverage Produce code coverage info using trace module -d, --die-on-missing Abort if no test data found for given command --, --longhelp Print help message for long options (common options) @@ -834,13 +835,34 @@ def run_test(gid,cmd_name): opt.quiet = oq_save return ret + def tool_api(cmd_name,args,out,opts,exec_code): + from mmgen.tool import tool_api + tool = tool_api() + if opts: + for o in opts: + if o.startswith('--type='): + tool.addrtype = o.split('=')[1] + pargs,kwargs = [],{} + for a in args: + if '=' in a: + a1,a2 = a.split('=') + kwargs[a1] = int(a2) if is_int(a2) else a2 + else: + pargs.append(a) + return getattr(tool,cmd_name)(*pargs,**kwargs) + for d in data: args,out,opts,exec_code = d + tuple([None] * (4-len(d))) stdin_input = None if args and type(args[0]) == bytes: stdin_input = args[0] args[0] = '-' - if opt.fork: + + if opt.tool_api: + if args and args[0 ]== '-': + continue + cmd_out = tool_api(cmd_name,args,out,opts,exec_code) + elif opt.fork: cmd_out = fork_cmd(cmd_name,args,out,opts,exec_code) else: if stdin_input and g.platform == 'win': @@ -923,6 +945,10 @@ sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:] cmd_args = opts.init(opts_data,add_opts=['use_old_ed25519']) +if opt.tool_api: + del tests['Wallet'] + del tests['File'] + import mmgen.tool as tool if opt.list_tests: