def _typeconvert_from_dfl(key): global opt gval = g.__dict__[key] uval = opt.__dict__[key] gtype = type(gval) try: opt.__dict__[key] = gtype(opt.__dict__[key]) except: d = { 'int': 'an integer', 'str': 'a string', 'float': 'a float', 'bool': 'a boolean value', } die(1, "'%s': invalid parameter for '--%s' option (not %s)" % ( opt.__dict__[key], key.replace("_","-"), d[gtype.__name__] )) if g.debug: Msg("Opt overriden by user:\n %-18s: %s" % ( key, ("%s -> %s" % (gval,uval)) ))
def override_from_cfg_file(cfg_data): from mmgen.util import die, strip_comments, set_for_type import re from mmgen.protocol import CoinProtocol for n, l in enumerate(cfg_data.splitlines(), 1): # DOS-safe l = strip_comments(l) if l == '': continue m = re.match(r'(\w+)\s+(\S+)$', l) if not m: die(2, "Parse error in file '{}', line {}".format(g.cfg_file, n)) name, val = m.groups() if name in g.cfg_file_opts: pfx, cfg_var = name.split('_', 1) if pfx in CoinProtocol.coins: tn = False cv1, cv2 = cfg_var.split('_', 1) if cv1 in ('mainnet', 'testnet'): tn, cfg_var = (cv1 == 'testnet'), cv2 cls, attr = CoinProtocol(pfx, tn), cfg_var else: cls, attr = g, name setattr( cls, attr, set_for_type(val, getattr(cls, attr), attr, src=g.cfg_file)) else: die(2, "'{}': unrecognized option in '{}'".format(name, g.cfg_file))
def init_fail(cls, e, m, e2=None, m2=None, objname=None, preformat=False): if preformat: errmsg = m else: fs = "{!r}: value cannot be converted to {} {}({})" e2_fmt = '({}) '.format(e2.args[0]) if e2 else '' errmsg = fs.format(m, objname or cls.__name__, e2_fmt, e.args[0]) if m2: errmsg = '{!r}\n{}'.format(m2, errmsg) from mmgen.globalvars import g from mmgen.util import die, msg if cls.on_fail == 'silent': return None # TODO: return False instead? elif cls.on_fail == 'return': if errmsg: msg(errmsg) return None # TODO: return False instead? elif g.traceback or cls.on_fail == 'raise': if hasattr(cls, 'exc'): raise cls.exc(errmsg) else: raise elif cls.on_fail == 'die': die(1, errmsg)
def get_data_from_config_file(): from mmgen.util import msg, die, check_or_create_dir check_or_create_dir(g.data_dir_root) # dies on error # https://wiki.debian.org/Python: # Debian (Ubuntu) sys.prefix is '/usr' rather than '/usr/local, so add 'local' # TODO - test for Windows # This must match the configuration in setup.py data = u'' try: with open(g.cfg_file, 'rb') as f: data = f.read().decode('utf8') except: cfg_template = os.path.join( *([sys.prefix] + (['share'], ['local', 'share'])[g.platform == 'linux'] + [g.proj_name.lower(), os.path.basename(g.cfg_file)])) try: with open(cfg_template, 'rb') as f: template_data = f.read() except: msg("WARNING: configuration template not found at '{}'".format( cfg_template)) else: try: with open(g.cfg_file, 'wb') as f: f.write(template_data) os.chmod(g.cfg_file, 0600) except: die( 2, "ERROR: unable to write to datadir '{}'".format( g.data_dir)) return data
def __call__(self, *args): self.__idcnt += 1 postdata = json.dumps({ 'version': '1.1', 'method': self.__serviceName, 'params': args, 'id': self.__idcnt}) try: self.__conn.request('POST', self.__url.path, postdata, { 'Host' : self.__url.hostname, 'User-Agent' : USER_AGENT, 'Authorization' : self.__authhdr, 'Content-type' : 'application/json' }) except: from mmgen.util import die,red die(1,red("Unable to connect to bitcoind")) 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 __init__(self, args, no_output=False): if opt.direct_exec: msg('') from subprocess import call, check_output f = (call, check_output)[bool(no_output)] ret = f([args[0]] + args[1:]) if f == call and ret != 0: die( 1, red('ERROR: process returned a non-zero exit status ({})'. format(ret))) else: if opt.pexpect_spawn: self.p = pexpect.spawn(args[0], args[1:], encoding='utf8') self.p.delaybeforesend = 0 else: self.p = PopenSpawn(args, encoding='utf8') # self.p.delaybeforesend = 0 # TODO: try this here too if opt.exact_output: self.p.logfile = sys.stdout self.req_exit_val = 0 self.skip_ok = False self.timeout = int(opt.pexpect_timeout or 0) or (60, 5)[bool( opt.debug_pexpect)] self.sent_value = None
def __init__(self,fn,ftype=None,write=False): self.name = fn self.dirname = os.path.dirname(fn) self.basename = os.path.basename(fn) self.ext = None self.ftype = ftype # This should be done before license msg instead # check_infile(fn) if not ftype: self.ext = get_extension(fn) if not (self.ext): die(2,"Unrecognized extension '.%s' for file '%s'" % (self.ext,fn)) # TODO: Check for Windows mode = (os.O_RDONLY,os.O_RDWR)[int(write)] import stat if stat.S_ISBLK(os.stat(fn).st_mode): try: fd = os.open(fn, mode) except OSError as e: if e.errno == 13: die(2,"'%s': permission denied" % fn) # if e.errno != 17: raise else: self.size = os.lseek(fd, 0, os.SEEK_END) os.close(fd) else: self.size = os.stat(fn).st_size
def copy_template_data(fn): try: with open(fn, 'wb') as f: f.write(template_data) os.chmod(fn, 0600) except: die(2, "ERROR: unable to write to datadir '{}'".format(g.data_dir))
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] if len(bad) > 1: die( 1, 'Conflicting options: %s' % ', '.join([fmt_opt(b) for b in bad]))
def ok(self): ret = self.p.wait() if ret != self.req_exit_val and not opt.coverage: die(1,red('test.py: spawned program exited with value {}'.format(ret))) if opt.profile: return if not self.skip_ok: sys.stderr.write(green('OK\n') if opt.exact_output or opt.verbose else (' OK\n')) return self
def __init__(self,trunner,cfgs,spawn): TestSuiteBase.__init__(self,trunner,cfgs,spawn) os.environ['MMGEN_TEST_SUITE_REGTEST'] = '1' if self.proto.testnet: die(2,'--testnet and --regtest options incompatible with regtest test suite') self.proto = init_proto(self.proto.coin,network='regtest') coin = self.proto.coin.lower() for k in rt_data: globals()[k] = rt_data[k][coin] if coin in rt_data[k] else None
def test_constants(self): msg('Testing generated constants: ') h = self.t_cls(b'foo') if h.H_init != self.H_ref: m = 'Generated constants H[] differ from reference value:\nReference:\n{}\nGenerated:\n{}' die(3,m.format([hex(n) for n in self.H_ref],[hex(n) for n in h.H_init])) if h.K != self.K_ref: m = 'Generated constants K[] differ from reference value:\nReference:\n{}\nGenerated:\n{}' die(3,m.format([hex(n) for n in self.K_ref],[hex(n) for n in h.K])) msg('OK\n')
def init_fail(m,on_fail,silent=False): from mmgen.util import die,msg if silent: m = '' if os.getenv('MMGEN_TRACEBACK'): raise ValueError,m elif on_fail == 'die': die(1,m) elif on_fail == 'return': if m: msg(m) return None # TODO: change to False elif on_fail == 'silent': return None # same here elif on_fail == 'raise': raise ValueError,m
def init_fail(m, on_fail, silent=False): if silent: m = '' from mmgen.util import die, msg if on_fail == 'die': die(1, m) elif on_fail == 'return': if m: msg(m) return None # TODO: change to False elif on_fail == 'silent': return None # same here elif on_fail == 'raise': raise ValueError, m
def setup(self): os.environ['MMGEN_BOGUS_WALLET_DATA'] = '' if g.testnet: die(2,'--testnet option incompatible with regtest test suite') try: shutil.rmtree(joinpath(self.tr.data_dir,'regtest')) except: pass os.environ['MMGEN_TEST_SUITE'] = '' # mnemonic is piped to stdin, so stop being a terminal t = self.spawn('mmgen-regtest',['-n','setup']) os.environ['MMGEN_TEST_SUITE'] = '1' for s in ('Starting setup','Creating','Mined','Creating','Creating','Setup complete'): t.expect(s) return t
def ok(self): ret = self.p.wait() if ret != self.req_exit_val and not opt.coverage: die( 1, red('test.py: spawned program exited with value {}'.format( ret))) if opt.profile: return if not self.skip_ok: sys.stderr.write( green('OK\n') if opt.exact_output or opt.verbose else ( ' OK\n')) return self
def setup(self): self.spawn('', msg_only=True) os.environ['MMGEN_BOGUS_WALLET_DATA'] = '' opts = ['--ports-shift=4', '--config=dev'] lf_arg = '--log-file=' + joinpath(self.tr.data_dir, 'parity.log') if g.platform == 'win': dc_dir = joinpath(os.environ['LOCALAPPDATA'], 'Parity', 'Ethereum', 'chains', 'DevelopmentChain') shutil.rmtree(dc_dir, ignore_errors=True) m1 = 'Please copy precompiled contract data to {d}/mm1 and {d}/mm2\n'.format( d=self.tmpdir) m2 = 'Then start parity on another terminal as follows:\n' m3 = ['parity', lf_arg] + opts m4 = '\nPress ENTER to continue: ' my_raw_input(m1 + m2 + ' '.join(m3) + m4) elif subprocess.call(['which', 'parity'], stdout=subprocess.PIPE) == 0: ss = 'parity.*--log-file=test/data_dir.*/parity.log' # allow for UTF8_DEBUG try: pid = subprocess.check_output(['pgrep', '-af', ss]).split()[0] os.kill(int(pid), 9) except: pass # '--base-path' doesn't work together with daemon mode, so we have to clobber the main dev chain dc_dir = joinpath( os.environ['HOME'], '.local/share/io.parity.ethereum/chains/DevelopmentChain') shutil.rmtree(dc_dir, ignore_errors=True) bdir = joinpath(self.tr.data_dir, 'parity') try: os.mkdir(bdir) except: pass redir = None if opt.exact_output else subprocess.PIPE pidfile = joinpath(self.tmpdir, parity_pid_fn) subprocess.check_call(['parity', lf_arg] + opts + ['daemon', pidfile], stderr=redir, stdout=redir) time.sleep(3) # race condition pid = self.read_from_tmpfile(parity_pid_fn) elif subprocess.call('netstat -tnl | grep -q 127.0.0.1:8549', shell=True) == 0: m1 = 'No parity executable found on system, but port 8549 is active!' m2 = 'Before continuing, you should probably run the command' m3 = 'test/test.py -X setup ethdev' m4 = 'on the remote host.' sys.stderr.write('{}\n{}\n{} {}\n'.format(m1, m2, cyan(m3), m4)) confirm_continue() else: die(1, 'No parity executable found!') return 'ok'
def find_files_in_dir(ftype, fdir, no_dups=False): if type(ftype) != type: die(3, "'{}': not a type".format(ftype)) from mmgen.seed import SeedSource if not issubclass(ftype, SeedSource): die(3, "'{}': not a recognized file type".format(ftype)) try: dirlist = os.listdir(fdir) except: die(3, "ERROR: unable to read directory '{}'".format(fdir)) matches = [ l for l in dirlist if l[-len(ftype.ext) - 1:] == '.' + ftype.ext ] if no_dups: if len(matches) > 1: die( 1, "ERROR: more than one {} file in directory '{}'".format( ftype.__name__, fdir)) return os.path.join(fdir, matches[0]) if len(matches) else None else: return [os.path.join(fdir, m) for m in matches]
def override_from_cfg_file(cfg_data): from mmgen.util import die, strip_comments, set_for_type import re for n, l in enumerate(cfg_data.splitlines(), 1): # DOS-safe l = strip_comments(l) if l == '': continue m = re.match(r'(\w+)\s+(\S+)$', l) if not m: die(2, "Parse error in file '{}', line {}".format(g.cfg_file, n)) name, val = m.groups() if name in g.cfg_file_opts: setattr(g, name, set_for_type(val, getattr(g, name), name, src=g.cfg_file)) else: die(2, "'{}': unrecognized option in '{}'".format(name, g.cfg_file))
def init_fail(m, on_fail): if os.getenv('MMGEN_TRACEBACK'): on_fail == 'raise' from mmgen.util import die, msg if on_fail == 'silent': return None # TODO: return False instead? elif on_fail == 'raise': raise ValueError, m elif on_fail == 'die': die(1, m) elif on_fail == 'return': if m: msg(m) return None # TODO: here too?
def __init__(self, fn, ftype=None, write=False): self.name = fn self.dirname = os.path.dirname(fn) self.basename = os.path.basename(fn) self.ext = get_extension(fn) self.ftype = None # the file's associated class self.mtime = None self.ctime = None self.atime = None from mmgen.seed import SeedSource from mmgen.tx import MMGenTX if ftype: if type(ftype) == type: if issubclass(ftype, SeedSource) or issubclass(ftype, MMGenTX): self.ftype = ftype # elif: # other MMGen file types else: die( 3, "'{}': not a recognized file type for SeedSource". format(ftype)) else: die(3, "'{}': not a class".format(ftype)) else: # TODO: other file types self.ftype = SeedSource.ext_to_type(self.ext) if not self.ftype: die( 3, "'{}': not a recognized extension for SeedSource".format( self.ext)) import stat if stat.S_ISBLK(os.stat(fn).st_mode): mode = (os.O_RDONLY, os.O_RDWR)[bool(write)] if g.platform == 'win': mode |= os.O_BINARY try: fd = os.open(fn, mode) except OSError as e: if e.errno == 13: die(2, "'{}': permission denied".format(fn)) # if e.errno != 17: raise else: self.size = os.lseek(fd, 0, os.SEEK_END) os.close(fd) else: self.size = os.stat(fn).st_size self.mtime = os.stat(fn).st_mtime self.ctime = os.stat(fn).st_ctime self.atime = os.stat(fn).st_atime
def init_fail(cls,e,m,e2=None,m2=None,objname=None,preformat=False): if preformat: errmsg = m else: fs = "{!r}: value cannot be converted to {} {}({})" e2_fmt = '({}) '.format(e2.args[0]) if e2 else '' errmsg = fs.format(m,objname or cls.__name__,e2_fmt,e.args[0]) if m2: errmsg = '{!r}\n{}'.format(m2,errmsg) from mmgen.globalvars import g if g.traceback: cls.on_fail == 'raise' from mmgen.util import die,msg if cls.on_fail == 'silent': return None # TODO: return False instead? elif cls.on_fail == 'raise': raise ValueError(errmsg) elif cls.on_fail == 'die': die(1,errmsg) elif cls.on_fail == 'return': if errmsg: msg(errmsg) return None # TODO: here too?
def override_from_cfg_file(cfg_data): from mmgen.util import die,strip_comments,set_for_type import re from mmgen.protocol import CoinProtocol for n,l in enumerate(cfg_data.splitlines(),1): # DOS-safe l = strip_comments(l) if l == '': continue m = re.match(r'(\w+)\s+(\S+)$',l) if not m: die(2,"Parse error in file '{}', line {}".format(g.cfg_file,n)) name,val = m.groups() if name in g.cfg_file_opts: pfx,cfg_var = name.split('_',1) if pfx in CoinProtocol.coins: cls,attr = CoinProtocol(pfx,False),cfg_var else: cls,attr = g,name setattr(cls,attr,set_for_type(val,getattr(cls,attr),attr,src=g.cfg_file)) # pmsg(cls,attr,getattr(cls,attr)) else: die(2,"'{}': unrecognized option in '{}'".format(name,g.cfg_file))
def setup(self): self.spawn('',msg_only=True) os.environ['MMGEN_BOGUS_WALLET_DATA'] = '' opts = ['--ports-shift=4','--config=dev'] lf_arg = '--log-file=' + joinpath(self.tr.data_dir,'parity.log') if g.platform == 'win': dc_dir = joinpath(os.environ['LOCALAPPDATA'],'Parity','Ethereum','chains','DevelopmentChain') shutil.rmtree(dc_dir,ignore_errors=True) m1 = 'Please copy precompiled contract data to {d}/mm1 and {d}/mm2\n'.format(d=self.tmpdir) m2 = 'Then start parity on another terminal as follows:\n' m3 = ['parity',lf_arg] + opts m4 = '\nPress ENTER to continue: ' my_raw_input(m1 + m2 + ' '.join(m3) + m4) elif subprocess.call(['which','parity'],stdout=subprocess.PIPE) == 0: ss = 'parity.*--log-file=test/data_dir.*/parity.log' # allow for UTF8_DEBUG try: pid = subprocess.check_output(['pgrep','-af',ss]).split()[0] os.kill(int(pid),9) except: pass # '--base-path' doesn't work together with daemon mode, so we have to clobber the main dev chain dc_dir = joinpath(os.environ['HOME'],'.local/share/io.parity.ethereum/chains/DevelopmentChain') shutil.rmtree(dc_dir,ignore_errors=True) bdir = joinpath(self.tr.data_dir,'parity') try: os.mkdir(bdir) except: pass redir = None if opt.exact_output else subprocess.PIPE pidfile = joinpath(self.tmpdir,parity_pid_fn) subprocess.check_call(['parity',lf_arg] + opts + ['daemon',pidfile],stderr=redir,stdout=redir) time.sleep(3) # race condition pid = self.read_from_tmpfile(parity_pid_fn) elif subprocess.call('netstat -tnl | grep -q 127.0.0.1:8549',shell=True) == 0: m1 = 'No parity executable found on system, but port 8549 is active!' m2 = 'Before continuing, you should probably run the command' m3 = 'test/test.py -X setup ethdev' m4 = 'on the remote host.' sys.stderr.write('{}\n{}\n{} {}\n'.format(m1,m2,cyan(m3),m4)) confirm_continue() else: die(1,'No parity executable found!') return 'ok'
def __init__(self,args,no_output=False): if opt.direct_exec: msg('') from subprocess import call,check_output f = (call,check_output)[bool(no_output)] ret = f([args[0]] + args[1:]) if f == call and ret != 0: die(1,red('ERROR: process returned a non-zero exit status ({})'.format(ret))) else: if opt.pexpect_spawn: self.p = pexpect.spawn(args[0],args[1:],encoding='utf8') self.p.delaybeforesend = 0 else: self.p = PopenSpawn(args,encoding='utf8') # self.p.delaybeforesend = 0 # TODO: try this here too if opt.exact_output: self.p.logfile = sys.stdout self.req_exit_val = 0 self.skip_ok = False self.timeout = int(opt.pexpect_timeout or 0) or (60,5)[bool(opt.debug_pexpect)] self.sent_value = None
def __init__(self,fn,ftype=None,write=False): self.name = fn self.dirname = os.path.dirname(fn) self.basename = os.path.basename(fn) self.ext = get_extension(fn) self.ftype = None # the file's associated class self.mtime = None self.ctime = None self.atime = None from mmgen.seed import SeedSource from mmgen.tx import MMGenTX if ftype: if type(ftype) == type: if issubclass(ftype,SeedSource) or issubclass(ftype,MMGenTX): self.ftype = ftype # elif: # other MMGen file types else: die(3,"'{}': not a recognized file type for SeedSource".format(ftype)) else: die(3,"'{}': not a class".format(ftype)) else: # TODO: other file types self.ftype = SeedSource.ext_to_type(self.ext) if not self.ftype: die(3,"'{}': not a recognized extension for SeedSource".format(self.ext)) import stat if stat.S_ISBLK(os.stat(fn).st_mode): mode = (os.O_RDONLY,os.O_RDWR)[bool(write)] if g.platform == 'win': mode |= os.O_BINARY try: fd = os.open(fn, mode) except OSError as e: if e.errno == 13: die(2,"'{}': permission denied".format(fn)) # if e.errno != 17: raise else: self.size = os.lseek(fd, 0, os.SEEK_END) os.close(fd) else: self.size = os.stat(fn).st_size self.mtime = os.stat(fn).st_mtime self.ctime = os.stat(fn).st_ctime self.atime = os.stat(fn).st_atime
def find_files_in_dir(ftype,fdir,no_dups=False): if type(ftype) != type: die(3,"'{}': not a type".format(ftype)) from mmgen.seed import SeedSource if not issubclass(ftype,SeedSource): die(3,"'{}': not a recognized file type".format(ftype)) try: dirlist = os.listdir(fdir) except: die(3,"ERROR: unable to read directory '{}'".format(fdir)) matches = [l for l in dirlist if l[-len(ftype.ext)-1:]=='.'+ftype.ext] if no_dups: if len(matches) > 1: die(1,"ERROR: more than one {} file in directory '{}'".format(ftype.__name__,fdir)) return os.path.join(fdir,matches[0]) if len(matches) else None else: return [os.path.join(fdir,m) for m in matches]
""" test/pexpect.py: pexpect implementation for MMGen test suites """ import sys, os, time from mmgen.globalvars import g from mmgen.opts import opt from mmgen.util import msg, msg_r, vmsg, vmsg_r, rmsg, red, yellow, green, cyan, die, rdie from .common import * try: import pexpect from pexpect.popen_spawn import PopenSpawn except ImportError as e: die( 2, red('Pexpect module is missing. Cannnot run test suite ({!r})'.format( e))) def debug_pexpect_msg(p): if opt.debug_pexpect: msg('\n{}{}{}'.format(red('BEFORE ['), p.before, red(']'))) msg('{}{}{}'.format(red('MATCH ['), p.after, red(']'))) NL = '\n' class MMGenPexpect(object): def __init__(self, args, no_output=False):
def split_setup(self): if g.coin != 'BTC': die(1,'Test valid only for coin BTC') opt.coin = 'BTC' return self.setup()
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] if len(bad) > 1: die(1,'Conflicting options: %s' % ', '.join([fmt_opt(b) for b in bad]))
def check_opts(usr_opts): # Returns false if any check fails def opt_splits(val,sep,n,desc): sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'%s'" % sep try: l = val.split(sep) except: msg("'%s': invalid %s (not %s-separated list)" % (val,desc,sepword)) return False if len(l) == n: return True else: msg("'%s': invalid %s (%s %s-separated items required)" % (val,desc,n,sepword)) return False def opt_compares(val,op,target,desc,what=''): if what: what += ' ' if not eval('%s %s %s' % (val, op, target)): msg('%s: invalid %s (%snot %s %s)' % (val,desc,what,op,target)) return False return True def opt_is_int(val,desc): try: int(val) except: msg("'%s': invalid %s (not an integer)" % (val,desc)) return False return True def opt_is_in_list(val,lst,desc): if val not in lst: q,sep = (('',','),("'","','"))[type(lst[0]) == str] msg('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format( v=val,w=desc,q=q, o=sep.join([str(i) for i in sorted(lst)]) )) return False return True def opt_unrecognized(key,val,desc): msg("'%s': unrecognized %s for option '%s'" % (val,desc,fmt_opt(key))) return False def opt_display(key,val='',beg='For selected',end=':\n'): s = '%s=%s' % (fmt_opt(key),val) if val else fmt_opt(key) msg_r("%s option '%s'%s" % (beg,s,end)) global opt for key,val in [(k,getattr(opt,k)) for k in usr_opts]: desc = "parameter for '%s' option" % fmt_opt(key) from mmgen.util import check_infile,check_outfile,check_outdir # 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): die(1,'Hidden incog format output requested. You must supply' + " a file and offset with the '%s' option" % 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' 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: die(1, 'Option conflict:\n %s, with\n %s=%s' % ( 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,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],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 == '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(),CoinProtocol.coins.keys(),'coin'): return False elif key == 'rbf': if not g.proto.cap('rbf'): die(1,'--rbf requested, but {} does not support replace-by-fee transactions'.format(g.coin)) elif key in ('bob','alice'): from mmgen.regtest import daemon_dir m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize." try: os.stat(daemon_dir) 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(val,'>',0,desc): return False else: if g.debug: Msg("check_opts(): No test for opt '%s'" % key) return True
def copy_template_data(fn): try: with open(fn,'wb') as f: f.write(template_data) os.chmod(fn,0600) except: die(2,"ERROR: unable to write to datadir '{}'".format(g.data_dir))
def check_opts(usr_opts): # Returns false 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) except: msg("'{}': invalid {} (not {}-separated list)".format(val,desc,sepword)) return False if len(l) == n: return True else: msg("'{}': invalid {} ({} {}-separated items required)".format(val,desc,n,sepword)) return False def opt_compares(val,op_str,target,desc,what=''): 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 def opt_is_int(val,desc): try: int(val) except: msg("'{}': invalid {} (not an integer)".format(val,desc)) return False return True def opt_is_float(val,desc): try: float(val) except: msg("'{}': invalid {} (not a floating-point number)".format(val,desc)) return False return True def opt_is_in_list(val,lst,desc): if val not in lst: q,sep = (('',','),("'","','"))[type(lst[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 def opt_unrecognized(key,val,desc): msg("'{}': unrecognized {} for option '{}'".format(val,desc,fmt_opt(key))) return False 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)) from mmgen.util import check_infile,check_outfile,check_outdir # 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' 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'): from mmgen.regtest import daemon_dir m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize." try: os.stat(daemon_dir) 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) else: if g.debug: Msg("check_opts(): No test for opt '{}'".format(key)) return True
def check_opts(usr_opts): # Returns false if any check fails def opt_splits(val, sep, n, desc): sepword = 'comma' if sep == ',' else 'colon' if sep == ':' else "'%s'" % sep try: l = val.split(sep) except: msg("'%s': invalid %s (not %s-separated list)" % (val, desc, sepword)) return False if len(l) == n: return True else: msg("'%s': invalid %s (%s %s-separated items required)" % (val, desc, n, sepword)) return False def opt_compares(val, op, target, desc, what=''): if what: what += ' ' if not eval('%s %s %s' % (val, op, target)): msg('%s: invalid %s (%snot %s %s)' % (val, desc, what, op, target)) return False return True def opt_is_int(val, desc): try: int(val) except: msg("'%s': invalid %s (not an integer)" % (val, desc)) return False return True def opt_is_tx_fee(val, desc): from mmgen.tx import MMGenTX ret = MMGenTX().convert_fee_spec(val, 224, on_fail='return') if ret == False: msg("'{}': invalid {} (not a {} amount or satoshis-per-byte specification)" .format(val, desc, g.coin.upper())) elif ret != None and ret > g.max_tx_fee: msg("'{}': invalid {} (> max_tx_fee ({} {}))".format( val, desc, g.max_tx_fee, g.coin.upper())) else: return True return False def opt_is_in_list(val, lst, desc): if val not in lst: q, sep = (('', ','), ("'", "','"))[type(lst[0]) == str] msg('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format( v=val, w=desc, q=q, o=sep.join([str(i) for i in sorted(lst)]))) return False return True def opt_unrecognized(key, val, desc): msg("'%s': unrecognized %s for option '%s'" % (val, desc, fmt_opt(key))) return False def opt_display(key, val='', beg='For selected', end=':\n'): s = '%s=%s' % (fmt_opt(key), val) if val else fmt_opt(key) msg_r("%s option '%s'%s" % (beg, s, end)) global opt for key, val in [(k, getattr(opt, k)) for k in usr_opts]: desc = "parameter for '%s' option" % fmt_opt(key) from mmgen.util import check_infile, check_outfile, check_outdir # 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): die( 1, 'Hidden incog format output requested. You must supply' + " a file and offset with the '%s' option" % 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' 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: die( 1, 'Option conflict:\n %s, with\n %s=%s' % (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, 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], 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 == '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': if not opt_is_in_list(val.upper(), g.coins, 'coin'): return False else: if g.debug: Msg("check_opts(): No test for opt '%s'" % key) return True
def copy_template_data(fn): try: open(fn, 'wb').write(template_data.encode()) os.chmod(fn, 0o600) except: die(2, "ERROR: unable to write to datadir '{}'".format(g.data_dir))
def split_setup(self): if g.coin != 'BTC': die(1, 'Test valid only for coin BTC') opt.coin = 'BTC' return self.setup()
def check_opts(usr_opts): # Returns false 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) except: msg("'{}': invalid {} (not {}-separated list)".format( val, desc, sepword)) return False if len(l) == n: return True else: msg("'{}': invalid {} ({} {}-separated items required)".format( val, desc, n, sepword)) return False def opt_compares(val, op_str, target, desc, what=''): 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 def opt_is_int(val, desc): try: int(val) except: msg("'{}': invalid {} (not an integer)".format(val, desc)) return False return True def opt_is_float(val, desc): try: float(val) except: msg("'{}': invalid {} (not a floating-point number)".format( val, desc)) return False return True def opt_is_in_list(val, lst, desc): if val not in lst: q, sep = (('', ','), ("'", "','"))[type(lst[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 def opt_unrecognized(key, val, desc): msg("'{}': unrecognized {} for option '{}'".format( val, desc, fmt_opt(key))) return False 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)) from mmgen.util import check_infile, check_outfile, check_outdir # 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' 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, 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], 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(), CoinProtocol.coins.keys(), 'coin'): return False elif key == 'rbf': if not g.proto.cap('rbf'): die( 1, '--rbf requested, but {} does not support replace-by-fee transactions' .format(g.coin)) elif key in ('bob', 'alice'): from mmgen.regtest import daemon_dir m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize." try: os.stat(daemon_dir) 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(val, '>', 0, desc): return False else: if g.debug: Msg("check_opts(): No test for opt '{}'".format(key)) return True
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] if len(bad) > 1: die(1,'Conflicting options: {}'.format(', '.join(map(fmt_opt,bad))))
# along with this program. If not, see <http://www.gnu.org/licenses/>. """ test/pexpect.py: pexpect implementation for MMGen test suites """ import sys, os, time from mmgen.globalvars import g from mmgen.opts import opt from mmgen.util import msg, msg_r, vmsg, vmsg_r, rmsg, red, yellow, green, cyan, die, rdie from test.common import getrandstr try: import pexpect from pexpect.popen_spawn import PopenSpawn except: die(2, red('Pexpect module is missing. Cannnot run test suite')) def debug_pexpect_msg(p): if opt.debug_pexpect: msg('\n{}{}{}'.format(red('BEFORE ['), p.before, red(']'))) msg('{}{}{}'.format(red('MATCH ['), p.after, red(']'))) NL = '\n' class MMGenPexpect(object): def __init__(self, args, no_output=False): if opt.direct_exec:
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) if parse_only: return uopts,args,short_opts,long_opts,skipped_opts if g.debug_opts: opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args) # Save this for usage() global usage_txt usage_txt = opts_data['text']['usage'] # Transfer uopts into opt, setting program's opts + required opts to None if not set by user for o in ( tuple([s.rstrip('=') for s in long_opts] + add_opts + skipped_opts) + g.required_opts + g.common_opts ): setattr(opt,o,uopts[o] if o in uopts else None) if opt.version: Die(0,""" {pn} version {g.version} Part of the {g.proj_name} suite, an online/offline cryptocoin wallet for the command line. Copyright (C) {g.Cdates} {g.author} {g.email} """.format(g=g,pn=g.prog_name.upper()).lstrip('\n').rstrip()) if os.getenv('MMGEN_DEBUG_ALL'): for name in g.env_opts: if name[:11] == 'MMGEN_DEBUG': os.environ[name] = '1' # === Interaction with global vars begins here === # 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() if not opt.skip_cfg_file: override_from_cfg_file(get_data_from_cfg_file()) override_from_env() # User opt sets global var - do these here, before opt is set from g.global_sets_opt for k in (g.common_opts + g.opt_sets_global): if hasattr(opt,k): val = getattr(opt,k) 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 from mmgen.protocol import init_genonly_altcoins,CoinProtocol altcoin_trust_level = init_genonly_altcoins(opt.coin) # g.testnet is set, so we can set g.proto g.proto = CoinProtocol(g.coin,g.testnet) # global sets proto if g.daemon_data_dir: g.proto.daemon_data_dir = g.daemon_data_dir # g.proto is set, so we can set g.data_dir g.data_dir = os.path.normpath(os.path.join(g.data_dir_root,g.proto.data_subdir)) # 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) setattr(opt,'set_by_user',[]) for k in g.global_sets_opt: if k in opt.__dict__ 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]) if opt.show_hash_presets: _show_hash_presets() sys.exit(0) 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'] if g.debug_utf8: for k in opts_data: if type(opts_data[k]) == str: opts_data[k] += '-α' mmgen.share.Opts.print_help(opts_data,opt_filter) # exits if g.bob or g.alice: g.testnet = True g.regtest = True g.proto = CoinProtocol(g.coin,g.testnet) g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob]) from . import regtest as rt g.rpc_host = 'localhost' g.rpc_port = rt.rpc_port g.rpc_user = rt.rpc_user g.rpc_password = rt.rpc_password check_or_create_dir(g.data_dir) # g.data_dir is finalized, so now we can do this if g.regtest and hasattr(g.proto,'bech32_hrp_rt'): g.proto.bech32_hrp = g.proto.bech32_hrp_rt # Check user-set opts without modifying them if not check_opts(uopts): die(1,'Options checking failed') if hasattr(g,'cfg_options_changed'): ymsg("Warning: config file options have changed! See '{}' for details".format(g.cfg_file+'.sample')) from mmgen.util import my_raw_input my_raw_input('Hit ENTER to continue: ') if g.debug and g.prog_name != 'test.py': opt.verbose,opt.quiet = (True,None) if g.debug_opts: opt_postproc_debug() g.altcoin_data_dir = os.path.join(g.data_dir_root,'altcoins') warn_altcoins(altcoin_trust_level) # We don't need this data anymore del mmgen.share.Opts, opts_data return args
def copy_template_data(fn): try: open(fn,'wb').write(template_data.encode()) os.chmod(fn,0o600) except: die(2,"ERROR: unable to write to datadir '{}'".format(g.data_dir))
""" test/pexpect.py: pexpect implementation for MMGen test suites """ import sys,os,time from mmgen.globalvars import g from mmgen.opts import opt from mmgen.util import msg,msg_r,vmsg,vmsg_r,rmsg,red,yellow,green,cyan,die,rdie from test.common import getrandstr try: import pexpect from pexpect.popen_spawn import PopenSpawn except: die(2,red('Pexpect module is missing. Cannnot run test suite')) def debug_pexpect_msg(p): if opt.debug_pexpect: msg('\n{}{}{}'.format(red('BEFORE ['),p.before,red(']'))) msg('{}{}{}'.format(red('MATCH ['),p.after,red(']'))) NL = '\n' class MMGenPexpect(object): def __init__(self,args,no_output=False): if opt.direct_exec: msg('') from subprocess import call,check_output
def sort_by_age(self, key='mtime', reverse=False): if key not in ('atime', 'ctime', 'mtime'): die(1, "'{}': illegal sort key".format(key)) self.sort(key=lambda a: getattr(a, key), reverse=reverse)
def sort_by_age(self,key='mtime',reverse=False): if key not in ('atime','ctime','mtime'): die(1,"'{}': illegal sort key".format(key)) self.sort(key=lambda a: getattr(a,key),reverse=reverse)
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] if len(bad) > 1: die(1, 'Conflicting options: {}'.format(', '.join(map(fmt_opt, bad))))
def split_setup(self): if self.proto.coin != 'BTC': die(1,'Test valid only for coin BTC') self.coin = 'BTC' return self.setup()
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) if parse_only: return uopts, args, short_opts, long_opts, skipped_opts if g.debug_opts: opt_preproc_debug(short_opts, long_opts, skipped_opts, uopts, args) # Save this for usage() global usage_txt usage_txt = opts_data['text']['usage'] # Transfer uopts into opt, setting program's opts + required opts to None if not set by user for o in (tuple([s.rstrip('=') for s in long_opts] + add_opts + skipped_opts) + g.required_opts + g.common_opts): setattr(opt, o, uopts[o] if o in uopts else None) if opt.version: Die( 0, """ {pn} version {g.version} Part of the {g.proj_name} suite, an online/offline cryptocoin wallet for the command line. Copyright (C) {g.Cdates} {g.author} {g.email} """.format(g=g, pn=g.prog_name.upper()).lstrip('\n').rstrip()) if os.getenv('MMGEN_DEBUG_ALL'): for name in g.env_opts: if name[:11] == 'MMGEN_DEBUG': os.environ[name] = '1' # === Interaction with global vars begins here === # 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() if not opt.skip_cfg_file: override_from_cfg_file(get_data_from_cfg_file()) override_from_env() # User opt sets global var - do these here, before opt is set from g.global_sets_opt for k in (g.common_opts + g.opt_sets_global): if hasattr(opt, k): val = getattr(opt, k) 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 from mmgen.protocol import init_genonly_altcoins, CoinProtocol altcoin_trust_level = init_genonly_altcoins(opt.coin) # g.testnet is set, so we can set g.proto g.proto = CoinProtocol(g.coin, g.testnet) # global sets proto if g.daemon_data_dir: g.proto.daemon_data_dir = g.daemon_data_dir # g.proto is set, so we can set g.data_dir g.data_dir = os.path.normpath( os.path.join(g.data_dir_root, g.proto.data_subdir)) # 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) setattr(opt, 'set_by_user', []) for k in g.global_sets_opt: if k in opt.__dict__ 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]) if opt.show_hash_presets: _show_hash_presets() sys.exit(0) 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'] if g.debug_utf8: for k in opts_data: if type(opts_data[k]) == str: opts_data[k] += '-α' mmgen.share.Opts.print_help(opts_data, opt_filter) # exits if g.bob or g.alice: g.testnet = True g.regtest = True g.proto = CoinProtocol(g.coin, g.testnet) g.data_dir = os.path.join(g.data_dir_root, 'regtest', g.coin.lower(), ('alice', 'bob')[g.bob]) from . import regtest as rt g.rpc_host = 'localhost' g.rpc_port = rt.rpc_port g.rpc_user = rt.rpc_user g.rpc_password = rt.rpc_password check_or_create_dir( g.data_dir) # g.data_dir is finalized, so now we can do this if g.regtest and hasattr(g.proto, 'bech32_hrp_rt'): g.proto.bech32_hrp = g.proto.bech32_hrp_rt # Check user-set opts without modifying them if not check_opts(uopts): die(1, 'Options checking failed') if hasattr(g, 'cfg_options_changed'): ymsg("Warning: config file options have changed! See '{}' for details". format(g.cfg_file + '.sample')) from mmgen.util import my_raw_input my_raw_input('Hit ENTER to continue: ') if g.debug and g.prog_name != 'test.py': opt.verbose, opt.quiet = (True, None) if g.debug_opts: opt_postproc_debug() g.altcoin_data_dir = os.path.join(g.data_dir_root, 'altcoins') warn_altcoins(altcoin_trust_level) # We don't need this data anymore del mmgen.share.Opts, opts_data return args
def check_opts(usr_opts): # Returns false if any check fails def opt_splits(val,sep,n,desc): sepword = "comma" if sep == "," else ( "colon" if sep == ":" else ("'"+sep+"'")) try: l = val.split(sep) except: msg("'%s': invalid %s (not %s-separated list)" % (val,desc,sepword)) return False if len(l) == n: return True else: msg("'%s': invalid %s (%s %s-separated items required)" % (val,desc,n,sepword)) return False def opt_compares(val,op,target,desc,what=""): if what: what += " " if not eval("%s %s %s" % (val, op, target)): msg("%s: invalid %s (%snot %s %s)" % (val,desc,what,op,target)) return False return True def opt_is_int(val,desc): try: int(val) except: msg("'%s': invalid %s (not an integer)" % (val,desc)) return False return True def opt_is_in_list(val,lst,desc): if val not in lst: q,sep = ("'","','") if type(lst[0]) == str else ("",",") msg("{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}".format( v=val,w=desc,q=q, o=sep.join([str(i) for i in sorted(lst)]) )) return False return True def opt_unrecognized(key,val,desc): msg("'%s': unrecognized %s for option '%s'" % (val,desc,fmt_opt(key))) return False def opt_display(key,val='',beg="For selected",end=":\n"): s = "%s=%s" % (fmt_opt(key),val) if val else fmt_opt(key) msg_r("%s option '%s'%s" % (beg,s,end)) global opt for key,val in [(k,getattr(opt,k)) for k in usr_opts]: desc = "parameter for '%s' option" % fmt_opt(key) from mmgen.util import check_infile,check_outfile,check_outdir # 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 elif key == 'label': if not is_mmgen_wallet_label(val): msg("Illegal value for option '%s': '%s'" % (fmt_opt(key),val)) return False # NEW elif key in ('in_fmt','out_fmt'): from mmgen.seed import SeedSource,IncogWallet,Brainwallet,IncogWalletHidden sstype = SeedSource.fmt_code_to_sstype(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): die(1,"Hidden incog format output requested. You must supply" + " a file and offset with the '%s' option" % 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 if not opt_is_int(a[1],desc): return False if key == 'hidden_incog_input_params': check_infile(a[0],blkdev_ok=True) key2 = 'in_fmt' else: import os try: os.stat(a[0]) except: b = os.path.dirname(a[0]) if b: check_outdir(b) else: check_outfile(a[0],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: die(1, "Option conflict:\n %s, with\n %s=%s" % ( 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,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],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 else: if g.debug: Msg("check_opts(): No test for opt '%s'" % key) return True
def compare_hashes(self,dlen,data): sha2_ref = getattr(self.hashlib,self.desc)(data).hexdigest() ret = self.t_cls(data).hexdigest() if ret != sha2_ref: m ='\nHashes do not match!\nReference {d}: {}\nMMGen {d}: {}' die(3,m.format(sha2_ref,ret,d=self.desc.upper()))
oaction = "output" nargs = 0 elif invoked_as == "conv": desc = "Convert an {pnm} wallet from one format to another" opt_filter = None elif invoked_as == "chk": desc = "Check validity of an {pnm} wallet" opt_filter = "ehiHOlpPqrvz" iaction = "input" elif invoked_as == "passchg": desc = "Change the password, hash preset or label of an {pnm} wallet" opt_filter = "ehdiHkKOlLmpPqrSvz" iaction = "input" bw_note = "" else: die(1,"'%s': unrecognized invocation" % bn) opts_data = { # Can't use: share/Opts doesn't know anything about fmt codes # 'sets': [('hidden_incog_output_params',bool,'out_fmt','hi')], 'desc': desc.format(pnm=g.proj_name), 'usage': usage, 'options': """ -h, --help Print this help message. -d, --outdir= d Output files to directory 'd' instead of working dir. -e, --echo-passphrase Echo passphrases and other user input to screen. -i, --in-fmt= f {iaction} from wallet format 'f' (see FMT CODES below). -o, --out-fmt= f {oaction} to wallet format 'f' (see FMT CODES below). -H, --hidden-incog-input-params=f,o Read hidden incognito data from file 'f' at offset 'o' (comma-separated). -J, --hidden-incog-output-params=f,o Write hidden incognito data to file