|
@@ -21,9 +21,11 @@ opts.py: MMGen-specific options processing after generic processing by share.Op
|
|
|
"""
|
|
|
import sys,os,stat
|
|
|
|
|
|
-class opt(object):
|
|
|
+class opt_cls(object):
|
|
|
pass
|
|
|
+opt = opt_cls()
|
|
|
|
|
|
+from mmgen.exception import UserOptError
|
|
|
from mmgen.globalvars import g
|
|
|
import mmgen.share.Opts
|
|
|
from mmgen.util import *
|
|
@@ -36,7 +38,7 @@ def fmt_opt(o):
|
|
|
|
|
|
def die_on_incompatible_opts(incompat_list):
|
|
|
for group in incompat_list:
|
|
|
- bad = [k for k in opt.__dict__ if opt.__dict__[k] and k in group]
|
|
|
+ bad = [k for k in opt.__dict__ if k in group and getattr(opt,k) != None]
|
|
|
if len(bad) > 1:
|
|
|
die(1,'Conflicting options: {}'.format(', '.join(map(fmt_opt,bad))))
|
|
|
|
|
@@ -48,14 +50,14 @@ def _show_hash_presets():
|
|
|
msg(fs.format(i,*g.hash_presets[i]))
|
|
|
msg('N = memory usage (power of two), p = iterations (rounds)')
|
|
|
|
|
|
-def opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args):
|
|
|
+def opt_preproc_debug(po):
|
|
|
d = (
|
|
|
('Cmdline', ' '.join(sys.argv)),
|
|
|
- ('Short opts', short_opts),
|
|
|
- ('Long opts', long_opts),
|
|
|
- ('Skipped opts', skipped_opts),
|
|
|
- ('User-selected opts', uopts),
|
|
|
- ('Cmd args', args),
|
|
|
+ ('Short opts', po.short_opts),
|
|
|
+ ('Long opts', po.long_opts),
|
|
|
+ ('Skipped opts', po.skipped_opts),
|
|
|
+ ('User-selected opts', po.user_opts),
|
|
|
+ ('Cmd args', po.cmd_args),
|
|
|
)
|
|
|
Msg('\n=== opts.py debug ===')
|
|
|
for e in d:
|
|
@@ -75,17 +77,6 @@ def opt_postproc_debug():
|
|
|
Msg(' {:<20}: {}'.format(e, getattr(g,e)))
|
|
|
Msg('\n=== end opts.py debug ===\n')
|
|
|
|
|
|
-def opt_postproc_initializations():
|
|
|
- g.coin = g.coin.upper() # allow user to use lowercase
|
|
|
- g.dcoin = g.coin # the display coin; for ERC20 tokens, g.dcoin is set to the token symbol
|
|
|
-
|
|
|
-def set_data_dir_root():
|
|
|
- g.data_dir_root = os.path.normpath(os.path.expanduser(opt.data_dir)) if opt.data_dir else \
|
|
|
- os.path.join(g.home_dir,'.'+g.proj_name.lower())
|
|
|
-
|
|
|
- # mainnet and testnet share cfg file, as with Core
|
|
|
- g.cfg_file = os.path.join(g.data_dir_root,'{}.cfg'.format(g.proj_name.lower()))
|
|
|
-
|
|
|
def init_term_and_color():
|
|
|
from mmgen.term import set_terminal_vars
|
|
|
set_terminal_vars()
|
|
@@ -136,8 +127,33 @@ def common_opts_code(s):
|
|
|
cu_dfl=g.coin,
|
|
|
cu_all=' '.join(CoinProtocol.coins) )
|
|
|
|
|
|
+def show_common_opts_diff():
|
|
|
+
|
|
|
+ def common_opts_data_to_list():
|
|
|
+ for l in common_opts_data['text'].splitlines():
|
|
|
+ if l.startswith('--,'):
|
|
|
+ yield l.split()[1].split('=')[0][2:].replace('-','_')
|
|
|
+
|
|
|
+ def do_fmt(set_data):
|
|
|
+ return fmt_list(['--'+s.replace('_','-') for s in set_data],fmt='col',indent=' ')
|
|
|
+
|
|
|
+ a = set(g.common_opts)
|
|
|
+ b = set(common_opts_data_to_list())
|
|
|
+
|
|
|
+ m1 = 'g.common_opts - common_opts_data:\n {}\n'
|
|
|
+ msg(m1.format(do_fmt(a-b) if a-b else 'None'))
|
|
|
+
|
|
|
+ m2 = 'common_opts_data - g.common_opts (these do not set global var):\n{}\n'
|
|
|
+ msg(m2.format(do_fmt(b-a)))
|
|
|
+
|
|
|
+ m3 = 'common_opts_data ^ g.common_opts (these set global var):\n{}\n'
|
|
|
+ msg(m3.format(do_fmt(b.intersection(a))))
|
|
|
+
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
common_opts_data = {
|
|
|
# Most but not all of these set the corresponding global var
|
|
|
+ # View differences with show_common_opts_diff()
|
|
|
'text': """
|
|
|
--, --accept-defaults Accept defaults at all prompts
|
|
|
--, --coin=c Choose coin unit. Default: {cu_dfl}. Options: {cu_all}
|
|
@@ -168,23 +184,23 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
|
|
|
opts_data['text']['long_options'] = common_opts_data['text']
|
|
|
|
|
|
- uopts,args,short_opts,long_opts,skipped_opts = \
|
|
|
- mmgen.share.Opts.parse_opts(opts_data,opt_filter=opt_filter,parse_only=parse_only)
|
|
|
+ # po: user_opts cmd_args short_opts long_opts skipped_opts
|
|
|
+ po = mmgen.share.Opts.parse_opts(opts_data,opt_filter=opt_filter,parse_only=parse_only)
|
|
|
|
|
|
if parse_only:
|
|
|
- return uopts,args,short_opts,long_opts,skipped_opts
|
|
|
+ return po
|
|
|
|
|
|
if g.debug_opts:
|
|
|
- opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args)
|
|
|
+ opt_preproc_debug(po)
|
|
|
|
|
|
# Copy parsed opts to opt, setting values to None if not set by user
|
|
|
for o in (
|
|
|
- tuple(s.rstrip('=') for s in long_opts)
|
|
|
+ tuple(s.rstrip('=') for s in po.long_opts)
|
|
|
+ tuple(add_opts)
|
|
|
- + tuple(skipped_opts)
|
|
|
+ + tuple(po.skipped_opts)
|
|
|
+ g.required_opts
|
|
|
+ g.common_opts ):
|
|
|
- setattr(opt,o,uopts[o] if o in uopts else None)
|
|
|
+ setattr(opt,o,po.user_opts[o] if o in po.user_opts else None)
|
|
|
|
|
|
# Make this available to usage()
|
|
|
global usage_txt
|
|
@@ -197,17 +213,16 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
command line. Copyright (C){g.Cdates} {g.author} {g.email}
|
|
|
""".format(g=g,pn=g.prog_name.upper()),indent=' ').rstrip())
|
|
|
|
|
|
- if os.getenv('MMGEN_DEBUG_ALL'):
|
|
|
- for name in g.env_opts:
|
|
|
- if name[:11] == 'MMGEN_DEBUG':
|
|
|
- os.environ[name] = '1'
|
|
|
-
|
|
|
# === begin global var initialization === #
|
|
|
|
|
|
# NB: user opt --data-dir is actually g.data_dir_root
|
|
|
# cfg file is in g.data_dir_root, wallet and other data are in g.data_dir
|
|
|
- # We must set g.data_dir_root and g.cfg_file from cmdline before processing cfg file
|
|
|
- set_data_dir_root()
|
|
|
+ # We must set g.data_dir_root from --data-dir before processing cfg file
|
|
|
+ g.data_dir_root = (
|
|
|
+ os.path.normpath(os.path.expanduser(opt.data_dir))
|
|
|
+ if opt.data_dir else
|
|
|
+ os.path.join(g.home_dir,'.'+g.proj_name.lower()) )
|
|
|
+
|
|
|
check_or_create_dir(g.data_dir_root)
|
|
|
|
|
|
init_term_and_color()
|
|
@@ -228,12 +243,16 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
if val != None:
|
|
|
setattr(g,k,set_for_type(val,getattr(g,k),'--'+k))
|
|
|
|
|
|
- if g.regtest: g.testnet = True # These are equivalent for now
|
|
|
+ g.coin = g.coin.upper() # allow user to use lowercase
|
|
|
+ g.dcoin = g.coin # the display coin; for ERC20 tokens, g.dcoin is set to the token symbol
|
|
|
+
|
|
|
+ if g.regtest: # These are equivalent for now
|
|
|
+ g.testnet = True
|
|
|
|
|
|
g.network = 'testnet' if g.testnet else 'mainnet'
|
|
|
|
|
|
from mmgen.protocol import init_genonly_altcoins,CoinProtocol
|
|
|
- altcoin_trust_level = init_genonly_altcoins(opt.coin or 'btc')
|
|
|
+ altcoin_trust_level = init_genonly_altcoins(g.coin)
|
|
|
|
|
|
# g.testnet is finalized, so we can set g.proto
|
|
|
g.proto = CoinProtocol(g.coin,g.testnet)
|
|
@@ -250,11 +269,11 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
# - if opt is set, convert its type to that of global value
|
|
|
opt.set_by_user = []
|
|
|
for k in g.global_sets_opt:
|
|
|
- if k in opt.__dict__ and getattr(opt,k) != None:
|
|
|
+ if hasattr(opt,k) and getattr(opt,k) != None:
|
|
|
setattr(opt,k,set_for_type(getattr(opt,k),getattr(g,k),'--'+k))
|
|
|
opt.set_by_user.append(k)
|
|
|
else:
|
|
|
- setattr(opt,k,g.__dict__[k])
|
|
|
+ setattr(opt,k,getattr(g,k))
|
|
|
|
|
|
if opt.show_hash_presets:
|
|
|
_show_hash_presets()
|
|
@@ -263,16 +282,6 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
if opt.verbose:
|
|
|
opt.quiet = None
|
|
|
|
|
|
- die_on_incompatible_opts(g.incompatible_opts)
|
|
|
-
|
|
|
- opt_postproc_initializations()
|
|
|
-
|
|
|
- if opts_data['do_help']: # print help screen only after global vars are initialized
|
|
|
- if not 'code' in opts_data:
|
|
|
- opts_data['code'] = {}
|
|
|
- opts_data['code']['long_options'] = common_opts_data['code']
|
|
|
- mmgen.share.Opts.print_help(opts_data,opt_filter) # exits
|
|
|
-
|
|
|
if g.bob or g.alice:
|
|
|
g.testnet = True
|
|
|
g.regtest = True
|
|
@@ -284,20 +293,23 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
g.rpc_password = MMGenRegtest.rpc_password
|
|
|
g.rpc_port = MMGenRegtest(g.coin).d.rpc_port
|
|
|
|
|
|
- check_or_create_dir(g.data_dir) # g.data_dir is finalized, so now we can do this
|
|
|
+ # === end global var initialization === #
|
|
|
|
|
|
- # Check user-set opts without modifying them
|
|
|
- if not check_opts(uopts):
|
|
|
- die(1,'Options checking failed')
|
|
|
+ if opts_data['do_help']: # print help screen only after global vars are initialized
|
|
|
+ if not 'code' in opts_data:
|
|
|
+ opts_data['code'] = {}
|
|
|
+ opts_data['code']['long_options'] = common_opts_data['code']
|
|
|
+ mmgen.share.Opts.print_help(opts_data,opt_filter) # exits
|
|
|
+
|
|
|
+ die_on_incompatible_opts(g.incompatible_opts)
|
|
|
+
|
|
|
+ check_or_create_dir(g.data_dir) # g.data_dir is finalized, so we can create it
|
|
|
|
|
|
- # Check user-set opts against g.autoset_opts, setting opt if unset:
|
|
|
- if not check_opts2(uopts):
|
|
|
- die(1,'Options checking failed')
|
|
|
+ # Check user-set opts without modifying them
|
|
|
+ check_usr_opts(po.user_opts)
|
|
|
|
|
|
- if hasattr(g,'cfg_options_changed'):
|
|
|
- ymsg("Warning: config file options have changed! See '{}' for details".format(g.cfg_file+'.sample'))
|
|
|
- if not g.test_suite:
|
|
|
- my_raw_input('Hit ENTER to continue: ')
|
|
|
+ # Check all opts against g.autoset_opts, setting if unset
|
|
|
+ check_and_set_autoset_opts()
|
|
|
|
|
|
if g.debug and g.prog_name != 'test.py':
|
|
|
opt.verbose,opt.quiet = (True,None)
|
|
@@ -308,211 +320,237 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|
|
warn_altcoins(g.coin,altcoin_trust_level)
|
|
|
|
|
|
# We don't need this data anymore
|
|
|
- del mmgen.share.Opts, opts_data
|
|
|
+ del mmgen.share.Opts
|
|
|
+ for k in ('text','notes','code'):
|
|
|
+ if k in opts_data:
|
|
|
+ del opts_data[k]
|
|
|
+
|
|
|
+ return po.cmd_args
|
|
|
|
|
|
- return args
|
|
|
+def opt_is_tx_fee(key,val,desc): # 'key' must remain a placeholder
|
|
|
+
|
|
|
+ # contract data or non-standard startgas: disable fee checking
|
|
|
+ if hasattr(opt,'contract_data') and opt.contract_data:
|
|
|
+ return
|
|
|
+ if hasattr(opt,'tx_gas') and opt.tx_gas:
|
|
|
+ return
|
|
|
|
|
|
-def opt_is_tx_fee(val,desc):
|
|
|
from mmgen.tx import MMGenTX
|
|
|
tx = MMGenTX(offline=True)
|
|
|
- # TODO: size is just a guess; do this check after parsing tx file
|
|
|
+ # Size of 224 is just a ball-park figure to eliminate the most extreme cases at startup
|
|
|
+ # This check will be performed again once we know the true size
|
|
|
ret = tx.process_fee_spec(val,224,on_fail='return')
|
|
|
- # Non-standard startgas: disable fee checking
|
|
|
- if hasattr(opt,'contract_data') and opt.contract_data: ret = None
|
|
|
- if hasattr(opt,'tx_gas') and opt.tx_gas: ret = None
|
|
|
+
|
|
|
if ret == False:
|
|
|
- msg("'{}': invalid {}\n(not a {} amount or {} specification)".format(
|
|
|
+ raise UserOptError('{!r}: invalid {}\n(not a {} amount or {} specification)'.format(
|
|
|
val,desc,g.coin.upper(),tx.rel_fee_desc))
|
|
|
- elif ret != None and ret > g.proto.max_tx_fee:
|
|
|
- msg("'{}': invalid {}\n({} > max_tx_fee ({} {}))".format(
|
|
|
- val,desc,ret.fmt(fs='1.1'),g.proto.max_tx_fee,g.coin.upper()))
|
|
|
- else:
|
|
|
- return True
|
|
|
- return False
|
|
|
|
|
|
-def check_opts2(usr_opts): # Returns false if any check fails
|
|
|
-
|
|
|
- for key in [e for e in opt.__dict__ if not e.startswith('__')]:
|
|
|
- if key in g.autoset_opts:
|
|
|
- val = getattr(opt,key)
|
|
|
- d = g.autoset_opts[key]
|
|
|
- if d[0] == 'nocase_str':
|
|
|
- if val == None:
|
|
|
- setattr(opt,key,d[1][0])
|
|
|
- elif val.lower() not in d[1]:
|
|
|
- m = "{!r}: invalid parameter for option --{} (valid choices: '{}')"
|
|
|
- msg(m.format(val,key.replace('_','-'),"', '".join(d[1])))
|
|
|
- return False
|
|
|
-
|
|
|
- return True
|
|
|
+ if ret > g.proto.max_tx_fee:
|
|
|
+ raise UserOptError('{!r}: invalid {}\n({} > max_tx_fee ({} {}))'.format(
|
|
|
+ val,desc,ret.fmt(fs='1.1'),g.proto.max_tx_fee,g.coin.upper()))
|
|
|
|
|
|
-def check_opts(usr_opts): # Returns false if any check fails
|
|
|
+def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|
|
|
|
|
def opt_splits(val,sep,n,desc):
|
|
|
- sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'{}'".format(sep)
|
|
|
- try: l = val.split(sep)
|
|
|
+ sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else repr(sep)
|
|
|
+ try:
|
|
|
+ l = val.split(sep)
|
|
|
except:
|
|
|
- msg("'{}': invalid {} (not {}-separated list)".format(val,desc,sepword))
|
|
|
- return False
|
|
|
+ raise UserOptError('{!r}: invalid {} (not {}-separated list)'.format(val,desc,sepword))
|
|
|
|
|
|
- if len(l) == n: return True
|
|
|
- else:
|
|
|
- msg("'{}': invalid {} ({} {}-separated items required)".format(val,desc,n,sepword))
|
|
|
- return False
|
|
|
+ if len(l) != n:
|
|
|
+ raise UserOptError('{!r}: invalid {} ({} {}-separated items required)'.format(val,desc,n,sepword))
|
|
|
|
|
|
- def opt_compares(val,op_str,target,desc,what=''):
|
|
|
+ def opt_compares(val,op_str,target,desc,desc2=''):
|
|
|
import operator as o
|
|
|
op_f = { '<':o.lt, '<=':o.le, '>':o.gt, '>=':o.ge, '=':o.eq }[op_str]
|
|
|
- if what: what += ' '
|
|
|
if not op_f(val,target):
|
|
|
- msg('{}: invalid {} ({}not {} {})'.format(val,desc,what,op_str,target))
|
|
|
- return False
|
|
|
- return True
|
|
|
+ d2 = desc2 + ' ' if desc2 else ''
|
|
|
+ raise UserOptError('{}: invalid {} ({}not {} {})'.format(val,desc,d2,op_str,target))
|
|
|
|
|
|
def opt_is_int(val,desc):
|
|
|
- try: int(val)
|
|
|
- except:
|
|
|
- msg("'{}': invalid {} (not an integer)".format(val,desc))
|
|
|
- return False
|
|
|
- return True
|
|
|
+ if not is_int(val):
|
|
|
+ raise UserOptError('{!r}: invalid {} (not an integer)'.format(val,desc))
|
|
|
|
|
|
def opt_is_float(val,desc):
|
|
|
- try: float(val)
|
|
|
+ try:
|
|
|
+ float(val)
|
|
|
except:
|
|
|
- msg("'{}': invalid {} (not a floating-point number)".format(val,desc))
|
|
|
- return False
|
|
|
- return True
|
|
|
+ raise UserOptError('{!r}: invalid {} (not a floating-point number)'.format(val,desc))
|
|
|
|
|
|
- def opt_is_in_list(val,lst,desc):
|
|
|
- if val not in lst:
|
|
|
- q,sep = (('',','),("'","','"))[type(lst[0]) == str]
|
|
|
+ def opt_is_in_list(val,tlist,desc):
|
|
|
+ if val not in tlist:
|
|
|
+ q,sep = (('',','),("'","','"))[type(tlist[0]) == str]
|
|
|
fs = '{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'
|
|
|
- msg(fs.format(v=val,w=desc,q=q,o=sep.join(map(str,sorted(lst)))))
|
|
|
- return False
|
|
|
- return True
|
|
|
+ raise UserOptError(fs.format(v=val,w=desc,q=q,o=sep.join(map(str,sorted(tlist)))))
|
|
|
|
|
|
- def opt_unrecognized(key,val,desc):
|
|
|
- msg("'{}': unrecognized {} for option '{}'".format(val,desc,fmt_opt(key)))
|
|
|
- return False
|
|
|
+ def opt_unrecognized(key,val,desc='value'):
|
|
|
+ raise UserOptError('{!r}: unrecognized {} for option {!r}'.format(val,desc,fmt_opt(key)))
|
|
|
|
|
|
def opt_display(key,val='',beg='For selected',end=':\n'):
|
|
|
s = '{}={}'.format(fmt_opt(key),val) if val else fmt_opt(key)
|
|
|
- msg_r("{} option '{}'{}".format(beg,s,end))
|
|
|
-
|
|
|
- global opt
|
|
|
- for key,val in [(k,getattr(opt,k)) for k in usr_opts]:
|
|
|
-
|
|
|
- desc = "parameter for '{}' option".format(fmt_opt(key))
|
|
|
-
|
|
|
- # Check for file existence and readability
|
|
|
- if key in ('keys_from_file','mmgen_keys_from_file',
|
|
|
- 'passwd_file','keysforaddrs','comment_file'):
|
|
|
- check_infile(val) # exits on error
|
|
|
- continue
|
|
|
-
|
|
|
- if key == 'outdir':
|
|
|
- check_outdir(val) # exits on error
|
|
|
-# # NEW
|
|
|
- elif key in ('in_fmt','out_fmt'):
|
|
|
- from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
|
|
|
- sstype = SeedSource.fmt_code_to_type(val)
|
|
|
- if not sstype:
|
|
|
- return opt_unrecognized(key,val,'format code')
|
|
|
- if key == 'out_fmt':
|
|
|
- p = 'hidden_incog_output_params'
|
|
|
- if sstype == IncogWalletHidden and not getattr(opt,p):
|
|
|
- m1 = 'Hidden incog format output requested. '
|
|
|
- m2 = "You must supply a file and offset with the '{}' option"
|
|
|
- die(1,m1+m2.format(fmt_opt(p)))
|
|
|
- if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
|
|
|
- opt_display(key,val,beg='Selected',end=' ')
|
|
|
- opt_display('old_incog_fmt',beg='conflicts with',end=':\n')
|
|
|
- die(1,'Export to old incog wallet format unsupported')
|
|
|
- elif issubclass(sstype,Brainwallet):
|
|
|
- die(1,'Output to brainwallet format unsupported')
|
|
|
- elif key in ('hidden_incog_input_params','hidden_incog_output_params'):
|
|
|
- a = val.split(',')
|
|
|
- if len(a) < 2:
|
|
|
- opt_display(key,val)
|
|
|
- msg('Option requires two comma-separated arguments')
|
|
|
- return False
|
|
|
- fn,ofs = ','.join(a[:-1]),a[-1] # permit comma in filename
|
|
|
- if not opt_is_int(ofs,desc): return False
|
|
|
- if key == 'hidden_incog_input_params':
|
|
|
- check_infile(fn,blkdev_ok=True)
|
|
|
- key2 = 'in_fmt'
|
|
|
+ msg_r('{} option {!r}{}'.format(beg,s,end))
|
|
|
+
|
|
|
+ def chk_in_fmt(key,val,desc):
|
|
|
+ from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden
|
|
|
+ sstype = SeedSource.fmt_code_to_type(val)
|
|
|
+ if not sstype:
|
|
|
+ opt_unrecognized(key,val)
|
|
|
+ if key == 'out_fmt':
|
|
|
+ p = 'hidden_incog_output_params'
|
|
|
+ if sstype == IncogWalletHidden and not getattr(opt,p):
|
|
|
+ m1 = 'Hidden incog format output requested. '
|
|
|
+ m2 = 'You must supply a file and offset with the {!r} option'
|
|
|
+ raise UserOptError(m1+m2.format(fmt_opt(p)))
|
|
|
+ if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
|
|
|
+ opt_display(key,val,beg='Selected',end=' ')
|
|
|
+ opt_display('old_incog_fmt',beg='conflicts with',end=':\n')
|
|
|
+ raise UserOptError('Export to old incog wallet format unsupported')
|
|
|
+ elif issubclass(sstype,Brainwallet):
|
|
|
+ raise UserOptError('Output to brainwallet format unsupported')
|
|
|
+
|
|
|
+ chk_out_fmt = chk_in_fmt
|
|
|
+
|
|
|
+ def chk_hidden_incog_input_params(key,val,desc):
|
|
|
+ a = val.rsplit(',',1) # permit comma in filename
|
|
|
+ if len(a) != 2:
|
|
|
+ opt_display(key,val)
|
|
|
+ raise UserOptError('Option requires two comma-separated arguments')
|
|
|
+
|
|
|
+ fn,offset = a
|
|
|
+ opt_is_int(offset,desc)
|
|
|
+
|
|
|
+ if key == 'hidden_incog_input_params':
|
|
|
+ check_infile(fn,blkdev_ok=True)
|
|
|
+ key2 = 'in_fmt'
|
|
|
+ else:
|
|
|
+ try: os.stat(fn)
|
|
|
+ except:
|
|
|
+ b = os.path.dirname(fn)
|
|
|
+ if b: check_outdir(b)
|
|
|
else:
|
|
|
- try: os.stat(fn)
|
|
|
- except:
|
|
|
- b = os.path.dirname(fn)
|
|
|
- if b: check_outdir(b)
|
|
|
- else: check_outfile(fn,blkdev_ok=True)
|
|
|
- key2 = 'out_fmt'
|
|
|
- if hasattr(opt,key2):
|
|
|
- val2 = getattr(opt,key2)
|
|
|
- from mmgen.seed import IncogWalletHidden
|
|
|
- if val2 and val2 not in IncogWalletHidden.fmt_codes:
|
|
|
- fs = 'Option conflict:\n {}, with\n {}={}'
|
|
|
- die(1,fs.format(fmt_opt(key),fmt_opt(key2),val2))
|
|
|
- elif key == 'seed_len':
|
|
|
- if not opt_is_int(val,desc): return False
|
|
|
- if not opt_is_in_list(int(val),g.seed_lens,desc): return False
|
|
|
- elif key == 'hash_preset':
|
|
|
- if not opt_is_in_list(val,list(g.hash_presets.keys()),desc): return False
|
|
|
- elif key == 'brain_params':
|
|
|
- a = val.split(',')
|
|
|
- if len(a) != 2:
|
|
|
- opt_display(key,val)
|
|
|
- msg('Option requires two comma-separated arguments')
|
|
|
- return False
|
|
|
- d = 'seed length ' + desc
|
|
|
- if not opt_is_int(a[0],d): return False
|
|
|
- if not opt_is_in_list(int(a[0]),g.seed_lens,d): return False
|
|
|
- d = 'hash preset ' + desc
|
|
|
- if not opt_is_in_list(a[1],list(g.hash_presets.keys()),d): return False
|
|
|
- elif key == 'usr_randchars':
|
|
|
- if val == 0: continue
|
|
|
- if not opt_is_int(val,desc): return False
|
|
|
- if not opt_compares(val,'>=',g.min_urandchars,desc): return False
|
|
|
- if not opt_compares(val,'<=',g.max_urandchars,desc): return False
|
|
|
- elif key == 'tx_fee':
|
|
|
- if not opt_is_tx_fee(val,desc): return False
|
|
|
- elif key == 'tx_confs':
|
|
|
- if not opt_is_int(val,desc): return False
|
|
|
- if not opt_compares(val,'>=',1,desc): return False
|
|
|
- elif key == 'vsize_adj':
|
|
|
- if not opt_is_float(val,desc): return False
|
|
|
- ymsg('Adjusting transaction vsize by a factor of {:1.2f}'.format(float(val)))
|
|
|
- elif key == 'key_generator':
|
|
|
- if not opt_compares(val,'<=',len(g.key_generators),desc): return False
|
|
|
- if not opt_compares(val,'>',0,desc): return False
|
|
|
- elif key == 'coin':
|
|
|
- from mmgen.protocol import CoinProtocol
|
|
|
- if not opt_is_in_list(val.lower(),list(CoinProtocol.coins.keys()),'coin'): return False
|
|
|
- elif key == 'rbf':
|
|
|
- if not g.proto.cap('rbf'):
|
|
|
- msg('--rbf requested, but {} does not support replace-by-fee transactions'.format(g.coin))
|
|
|
- return False
|
|
|
- elif key in ('bob','alice'):
|
|
|
- m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize."
|
|
|
- from mmgen.regtest import MMGenRegtest
|
|
|
- try: os.stat(os.path.join(MMGenRegtest(g.coin).d.datadir,'regtest','debug.log'))
|
|
|
- except: die(1,m.format(g.proj_name.lower()))
|
|
|
- elif key == 'locktime':
|
|
|
- if not opt_is_int(val,desc): return False
|
|
|
- if not opt_compares(int(val),'>',0,desc): return False
|
|
|
- elif key == 'token':
|
|
|
- if not 'token' in g.proto.caps:
|
|
|
- msg("Coin '{}' does not support the --token option".format(g.coin))
|
|
|
- return False
|
|
|
- elif len(val) == 40 and is_hex_str(val):
|
|
|
- pass
|
|
|
- elif len(val) > 20 or not all(s.isalnum() for s in val):
|
|
|
- msg("u'{}: invalid parameter for --token option".format(val))
|
|
|
- return False
|
|
|
- elif key == 'contract_data':
|
|
|
- check_infile(val)
|
|
|
+ check_outfile(fn,blkdev_ok=True)
|
|
|
+ key2 = 'out_fmt'
|
|
|
+
|
|
|
+ if hasattr(opt,key2):
|
|
|
+ val2 = getattr(opt,key2)
|
|
|
+ from mmgen.seed import IncogWalletHidden
|
|
|
+ if val2 and val2 not in IncogWalletHidden.fmt_codes:
|
|
|
+ fs = 'Option conflict:\n {}, with\n {}={}'
|
|
|
+ raise UserOptError(fs.format(fmt_opt(key),fmt_opt(key2),val2))
|
|
|
+
|
|
|
+ chk_hidden_incog_output_params = chk_hidden_incog_input_params
|
|
|
+
|
|
|
+ def chk_seed_len(key,val,desc):
|
|
|
+ opt_is_int(val,desc)
|
|
|
+ opt_is_in_list(int(val),g.seed_lens,desc)
|
|
|
+
|
|
|
+ def chk_hash_preset(key,val,desc):
|
|
|
+ opt_is_in_list(val,list(g.hash_presets.keys()),desc)
|
|
|
+
|
|
|
+ def chk_brain_params(key,val,desc):
|
|
|
+ a = val.split(',')
|
|
|
+ if len(a) != 2:
|
|
|
+ opt_display(key,val)
|
|
|
+ raise UserOptError('Option requires two comma-separated arguments')
|
|
|
+ opt_is_int(a[0],'seed length '+desc)
|
|
|
+ opt_is_in_list(int(a[0]),g.seed_lens,'seed length '+desc)
|
|
|
+ opt_is_in_list(a[1],list(g.hash_presets.keys()),'hash preset '+desc)
|
|
|
+
|
|
|
+ def chk_usr_randchars(key,val,desc):
|
|
|
+ if val == 0:
|
|
|
+ return
|
|
|
+ opt_is_int(val,desc)
|
|
|
+ opt_compares(val,'>=',g.min_urandchars,desc)
|
|
|
+ opt_compares(val,'<=',g.max_urandchars,desc)
|
|
|
+
|
|
|
+ def chk_tx_fee(key,val,desc):
|
|
|
+ opt_is_tx_fee(key,val,desc)
|
|
|
+
|
|
|
+ def chk_tx_confs(key,val,desc):
|
|
|
+ opt_is_int(val,desc)
|
|
|
+ opt_compares(val,'>=',1,desc)
|
|
|
+
|
|
|
+ def chk_vsize_adj(key,val,desc):
|
|
|
+ opt_is_float(val,desc)
|
|
|
+ ymsg('Adjusting transaction vsize by a factor of {:1.2f}'.format(float(val)))
|
|
|
+
|
|
|
+ def chk_key_generator(key,val,desc):
|
|
|
+ opt_compares(val,'<=',len(g.key_generators),desc)
|
|
|
+ opt_compares(val,'>',0,desc)
|
|
|
+
|
|
|
+ def chk_coin(key,val,desc):
|
|
|
+ from mmgen.protocol import CoinProtocol
|
|
|
+ opt_is_in_list(val.lower(),list(CoinProtocol.coins.keys()),'coin')
|
|
|
+
|
|
|
+ def chk_rbf(key,val,desc):
|
|
|
+ if not g.proto.cap('rbf'):
|
|
|
+ m = '--rbf requested, but {} does not support replace-by-fee transactions'
|
|
|
+ raise UserOptError(m.format(g.coin))
|
|
|
+
|
|
|
+ def chk_bob(key,val,desc):
|
|
|
+ m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize."
|
|
|
+ from mmgen.regtest import MMGenRegtest
|
|
|
+ try:
|
|
|
+ os.stat(os.path.join(MMGenRegtest(g.coin).d.datadir,'regtest','debug.log'))
|
|
|
+ except:
|
|
|
+ raise UserOptError(m.format(g.proj_name.lower()))
|
|
|
+
|
|
|
+ chk_alice = chk_bob
|
|
|
+
|
|
|
+ def chk_locktime(key,val,desc):
|
|
|
+ opt_is_int(val,desc)
|
|
|
+ opt_compares(int(val),'>',0,desc)
|
|
|
+
|
|
|
+ def chk_token(key,val,desc):
|
|
|
+ if not 'token' in g.proto.caps:
|
|
|
+ raise UserOptError('Coin {!r} does not support the --token option'.format(g.coin))
|
|
|
+ if len(val) == 40 and is_hex_str(val):
|
|
|
+ return
|
|
|
+ if len(val) > 20 or not all(s.isalnum() for s in val):
|
|
|
+ raise UserOptError('{!r}: invalid parameter for --token option'.format(val))
|
|
|
+
|
|
|
+ cfuncs = { k:v for k,v in locals().items() if k.startswith('chk_') }
|
|
|
+
|
|
|
+ for key in usr_opts:
|
|
|
+ val = getattr(opt,key)
|
|
|
+ desc = 'parameter for {!r} option'.format(fmt_opt(key))
|
|
|
+
|
|
|
+ if key in g.infile_opts:
|
|
|
+ check_infile(val) # file exists and is readable - dies on error
|
|
|
+ elif key == 'outdir':
|
|
|
+ check_outdir(val) # dies on error
|
|
|
+ elif 'chk_'+key in cfuncs:
|
|
|
+ cfuncs['chk_'+key](key,val,desc)
|
|
|
+ elif g.debug:
|
|
|
+ Msg('check_usr_opts(): No test for opt {!r}'.format(key))
|
|
|
+
|
|
|
+def check_and_set_autoset_opts(): # Raises exception if any check fails
|
|
|
+
|
|
|
+ def nocase_str(key,val,asd):
|
|
|
+ if val.lower() in asd.choices:
|
|
|
+ return True
|
|
|
else:
|
|
|
- if g.debug: Msg("check_opts(): No test for opt '{}'".format(key))
|
|
|
+ return 'one of'
|
|
|
|
|
|
- return True
|
|
|
+ def nocase_pfx(key,val,asd):
|
|
|
+ cs = [s.startswith(val.lower()) for s in asd.choices]
|
|
|
+ if cs.count(True) == 1:
|
|
|
+ return cs.index(True)
|
|
|
+ else:
|
|
|
+ return 'unique substring of'
|
|
|
+
|
|
|
+ for key,asd in g.autoset_opts.items():
|
|
|
+ if hasattr(opt,key):
|
|
|
+ val = getattr(opt,key)
|
|
|
+ if val is None:
|
|
|
+ setattr(opt,key,asd.choices[0])
|
|
|
+ else:
|
|
|
+ ret = locals()[asd.type](key,val,asd)
|
|
|
+ if type(ret) is str:
|
|
|
+ m = '{!r}: invalid parameter for option --{} (not {}: {})'
|
|
|
+ raise UserOptError(m.format(val,key.replace('_','-'),ret,fmt_list(asd.choices)))
|
|
|
+ elif ret is True:
|
|
|
+ setattr(opt,key,val)
|
|
|
+ else:
|
|
|
+ setattr(opt,key,asd.choices[ret])
|