test.py 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. #!/usr/bin/python
  2. # Chdir to repo root.
  3. # Since script is not in repo root, fix sys.path so that modules are
  4. # imported from repo, not system.
  5. import sys,os
  6. pn = os.path.dirname(sys.argv[0])
  7. os.chdir(os.path.join(pn,os.pardir))
  8. sys.path.__setitem__(0,os.path.abspath(os.curdir))
  9. import mmgen.config as g
  10. import mmgen.opt as opt
  11. from mmgen.util import msgrepr,msgrepr_exit,Msg
  12. from mmgen.test import *
  13. hincog_fn = "rand_data"
  14. hincog_bytes = 1024*1024
  15. hincog_offset = 98765
  16. hincog_seedlen = 256
  17. incog_id_fn = "incog_id"
  18. non_mmgen_fn = "btckey"
  19. cfgs = {
  20. '6': {
  21. 'name': "reference wallet check",
  22. 'wallet_label': "test.py reference wallet (password 'abc')",
  23. 'bw_passwd': "abc",
  24. 'bw_hashparams': "256,1",
  25. 'key_id': "98831F3A",
  26. 'addrfile_chk': "6FEF 6FB9 7B13 5D91 854A 0BD3",
  27. 'keyaddrfile_chk': "9F2D D781 1812 8BAD C396 9DEB",
  28. 'wpasswd': "reference password",
  29. 'tmpdir': "test/tmp6",
  30. 'kapasswd': "",
  31. 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses
  32. 'dep_generators': {
  33. 'mmdat': "refwalletgen",
  34. 'addrs': "refaddrgen",
  35. 'akeys.mmenc': "refkeyaddrgen"
  36. },
  37. },
  38. '1': {
  39. 'tmpdir': "test/tmp1",
  40. 'wpasswd': "Dorian",
  41. 'kapasswd': "Grok the blockchain",
  42. 'addr_idx_list': "12,99,5-10,5,12", # 8 addresses
  43. 'dep_generators': {
  44. 'mmdat': "walletgen",
  45. 'addrs': "addrgen",
  46. 'raw': "txcreate",
  47. 'sig': "txsign",
  48. 'mmwords': "export_mnemonic",
  49. 'mmseed': "export_seed",
  50. 'mmincog': "export_incog",
  51. 'mmincox': "export_incog_hex",
  52. hincog_fn: "export_incog_hidden",
  53. incog_id_fn: "export_incog_hidden",
  54. 'akeys.mmenc': "keyaddrgen"
  55. },
  56. },
  57. '2': {
  58. 'tmpdir': "test/tmp2",
  59. 'wpasswd': "Hodling away",
  60. 'addr_idx_list': "37,45,3-6,22-23", # 8 addresses
  61. 'seed_len': 128,
  62. 'dep_generators': {
  63. 'mmdat': "walletgen2",
  64. 'addrs': "addrgen2",
  65. 'raw': "txcreate2",
  66. 'sig': "txsign2",
  67. 'mmwords': "export_mnemonic2",
  68. },
  69. },
  70. '3': {
  71. 'tmpdir': "test/tmp3",
  72. 'wpasswd': "Major miner",
  73. 'addr_idx_list': "73,54,1022-1023,2-5", # 8 addresses
  74. 'dep_generators': {
  75. 'mmdat': "walletgen3",
  76. 'addrs': "addrgen3",
  77. 'raw': "txcreate3",
  78. 'sig': "txsign3"
  79. },
  80. },
  81. '4': {
  82. 'tmpdir': "test/tmp4",
  83. 'wpasswd': "Hashrate rising",
  84. 'addr_idx_list': "63,1004,542-544,7-9", # 8 addresses
  85. 'seed_len': 192,
  86. 'dep_generators': {
  87. 'mmdat': "walletgen4",
  88. 'mmbrain': "walletgen4",
  89. 'addrs': "addrgen4",
  90. 'raw': "txcreate4",
  91. 'sig': "txsign4",
  92. },
  93. 'bw_filename': "brainwallet.mmbrain",
  94. 'bw_params': "192,1",
  95. },
  96. '5': {
  97. 'tmpdir': "test/tmp5",
  98. 'wpasswd': "My changed password",
  99. 'dep_generators': {
  100. 'mmdat': "passchg",
  101. },
  102. },
  103. '9': {
  104. 'tmpdir': "test/tmp9",
  105. 'tool_enc_passwd': "Scrypt it, don't hash it!",
  106. 'tool_enc_reftext':
  107. "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n",
  108. 'tool_enc_infn': "tool_encrypt.in",
  109. 'tool_enc_ref_infn': "tool_encrypt_ref.in",
  110. 'dep_generators': {
  111. 'tool_encrypt.in': "tool_encrypt",
  112. 'tool_encrypt.in.mmenc': "tool_encrypt",
  113. 'tool_encrypt_ref.in': "tool_encrypt_ref",
  114. 'tool_encrypt_ref.in.mmenc': "tool_encrypt_ref",
  115. },
  116. },
  117. }
  118. from collections import OrderedDict
  119. cmd_data = OrderedDict([
  120. # test description depends
  121. ['refwalletgen', (6,'reference wallet seed ID', [[[],6]])],
  122. ['refaddrgen', (6,'reference wallet address checksum', [[["mmdat"],6]])],
  123. ['refkeyaddrgen', (6,'reference wallet key-address checksum', [[["mmdat"],6]])],
  124. ['walletgen', (1,'wallet generation', [[[],1]])],
  125. ['walletchk', (1,'wallet check', [[["mmdat"],1]])],
  126. ['passchg', (5,'password, label and hash preset change',[[["mmdat"],1]])],
  127. ['walletchk_newpass',(5,'wallet check with new pw, label and hash preset',[[["mmdat"],5]])],
  128. ['addrgen', (1,'address generation', [[["mmdat"],1]])],
  129. ['addrimport', (1,'address import', [[["addrs"],1]])],
  130. ['txcreate', (1,'transaction creation', [[["addrs"],1]])],
  131. ['txsign', (1,'transaction signing', [[["mmdat","raw"],1]])],
  132. ['txsend', (1,'transaction sending', [[["sig"],1]])],
  133. ['export_seed', (1,'seed export to mmseed format', [[["mmdat"],1]])],
  134. ['export_mnemonic', (1,'seed export to mmwords format', [[["mmdat"],1]])],
  135. ['export_incog', (1,'seed export to mmincog format', [[["mmdat"],1]])],
  136. ['export_incog_hex',(1,'seed export to mmincog hex format', [[["mmdat"],1]])],
  137. ['export_incog_hidden',(1,'seed export to hidden mmincog format', [[["mmdat"],1]])],
  138. ['addrgen_seed', (1,'address generation from mmseed file', [[["mmseed","addrs"],1]])],
  139. ['addrgen_mnemonic',(1,'address generation from mmwords file',[[["mmwords","addrs"],1]])],
  140. ['addrgen_incog', (1,'address generation from mmincog file',[[["mmincog","addrs"],1]])],
  141. ['addrgen_incog_hex',(1,'address generation from mmincog hex file',[[["mmincox","addrs"],1]])],
  142. ['addrgen_incog_hidden',(1,'address generation from hidden mmincog file', [[[hincog_fn,"addrs"],1]])],
  143. ['keyaddrgen', (1,'key-address file generation', [[["mmdat"],1]])],
  144. ['txsign_keyaddr',(1,'transaction signing with key-address file', [[["akeys.mmenc","raw"],1]])],
  145. # ['walletgen2',(2,'wallet generation (2)', [])],
  146. ['walletgen2',(2,'wallet generation (2), 128-bit seed', [])],
  147. ['addrgen2', (2,'address generation (2)', [[["mmdat"],2]])],
  148. ['txcreate2', (2,'transaction creation (2)', [[["addrs"],2]])],
  149. ['txsign2', (2,'transaction signing, two transactions',[[["mmdat","raw"],1],[["mmdat","raw"],2]])],
  150. ['export_mnemonic2', (2,'seed export to mmwords format (2)',[[["mmdat"],2]])],
  151. # ['export_mnemonic2', (2,'seed export to mmwords format (2), 128-bit seed (WIP)',[[["mmdat"],2]])],
  152. ['walletgen3',(3,'wallet generation (3)', [])],
  153. ['addrgen3', (3,'address generation (3)', [[["mmdat"],3]])],
  154. ['txcreate3', (3,'tx creation with inputs and outputs from two wallets', [[["addrs"],1],[["addrs"],3]])],
  155. ['txsign3', (3,'tx signing with inputs and outputs from two wallets',[[["mmdat"],1],[["mmdat","raw"],3]])],
  156. ['walletgen4',(4,'wallet generation (4) (brainwallet)', [])],
  157. # ['walletgen4',(4,'wallet generation (4) (brainwallet, 192-bit seed (WIP))', [])],
  158. ['addrgen4', (4,'address generation (4)', [[["mmdat"],4]])],
  159. ['txcreate4', (4,'tx creation with inputs and outputs from four seed sources, plus non-MMGen inputs and outputs', [[["addrs"],1],[["addrs"],2],[["addrs"],3],[["addrs"],4]])],
  160. ['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet and brainwallet, plus non-MMGen inputs and outputs', [[["mmincog"],1],[["mmwords"],2],[["mmdat"],3],[["mmbrain","raw"],4]])],
  161. ['tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [])],
  162. ['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)",
  163. [[[cfgs['9']['tool_enc_infn'],
  164. cfgs['9']['tool_enc_infn']+".mmenc"],9]])],
  165. ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])],
  166. ['tool_decrypt_ref', (9,"'mmgen-tool decrypt' (reference text)",
  167. [[[cfgs['9']['tool_enc_ref_infn'],
  168. cfgs['9']['tool_enc_ref_infn']+".mmenc"],9]])],
  169. ['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])],
  170. ])
  171. utils = {
  172. 'check_deps': 'check dependencies for specified command',
  173. 'clean': 'clean specified tmp dir(s) 1,2,3,4,5 or 6 (no arg = all dirs)',
  174. }
  175. addrs_per_wallet = 8
  176. # total of two outputs must be < 10 BTC
  177. for k in cfgs.keys():
  178. cfgs[k]['amts'] = [0,0]
  179. for idx,mod in (0,6),(1,4):
  180. cfgs[k]['amts'][idx] = "%s.%s" % ((getrandnum(2) % mod), str(getrandnum(4))[:5])
  181. meta_cmds = OrderedDict([
  182. ['ref', (6,("refwalletgen","refaddrgen","refkeyaddrgen"))],
  183. ['gen', (1,("walletgen","walletchk","addrgen"))],
  184. ['pass', (5,("passchg","walletchk_newpass"))],
  185. ['tx', (1,("txcreate","txsign","txsend"))],
  186. ['export', (1,[k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1])],
  187. ['gen_sp', (1,[k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1])],
  188. ['online', (1,("keyaddrgen","txsign_keyaddr"))],
  189. ['2', (2,[k for k in cmd_data if cmd_data[k][0] == 2])],
  190. ['3', (3,[k for k in cmd_data if cmd_data[k][0] == 3])],
  191. ['4', (4,[k for k in cmd_data if cmd_data[k][0] == 4])],
  192. ['tool', (9,("tool_encrypt","tool_decrypt","tool_encrypt_ref","tool_decrypt_ref","tool_find_incog_data"))],
  193. ])
  194. opts_data = {
  195. 'desc': "Test suite for the MMGen suite",
  196. 'usage':"[options] [command or metacommand]",
  197. 'options': """
  198. -h, --help Print this help message
  199. -b, --buf-keypress Use buffered keypresses as with real human input
  200. -d, --debug-scripts Turn on debugging output in executed scripts
  201. -D, --direct-exec Bypass pexpect and execute a command directly (for
  202. debugging only)
  203. -e, --exact-output Show the exact output of the MMGen script(s) being run
  204. -l, --list-cmds List and describe the tests and commands in the test suite
  205. -p, --pause Pause between tests, resuming on keypress
  206. -q, --quiet Produce minimal output. Suppress dependency info
  207. -s, --system Test scripts and modules installed on system rather than
  208. those in the repo root
  209. -v, --verbose Produce more verbose output
  210. """,
  211. 'notes': """
  212. If no command is given, the whole suite of tests is run.
  213. """
  214. }
  215. cmd_args = opt.opts.init(opts_data)
  216. if opt.system: sys.path.pop(0)
  217. if opt.debug_scripts: os.environ["MMGEN_DEBUG"] = "1"
  218. if opt.buf_keypress:
  219. send_delay = 0.3
  220. else:
  221. send_delay = 0
  222. os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
  223. if opt.debug: opt.verbose = True
  224. if opt.exact_output:
  225. def msg(s): pass
  226. vmsg = vmsg_r = msg_r = msg
  227. else:
  228. def msg(s): sys.stderr.write(s+"\n")
  229. def vmsg(s):
  230. if opt.verbose: sys.stderr.write(s+"\n")
  231. def msg_r(s): sys.stderr.write(s)
  232. def vmsg_r(s):
  233. if opt.verbose: sys.stderr.write(s)
  234. stderr_save = sys.stderr
  235. def silence():
  236. if not (opt.verbose or opt.exact_output):
  237. sys.stderr = open("/dev/null","a")
  238. def end_silence():
  239. if not (opt.verbose or opt.exact_output):
  240. sys.stderr = stderr_save
  241. def errmsg(s): stderr_save.write(s+"\n")
  242. def errmsg_r(s): stderr_save.write(s)
  243. if opt.list_cmds:
  244. fs = " {:<{w}} - {}"
  245. Msg("Available commands:")
  246. w = max([len(i) for i in cmd_data])
  247. for cmd in cmd_data:
  248. Msg(fs.format(cmd,cmd_data[cmd][1],w=w))
  249. Msg("\nAvailable metacommands:")
  250. w = max([len(i) for i in meta_cmds])
  251. for cmd in meta_cmds:
  252. Msg(fs.format(cmd," + ".join(meta_cmds[cmd][1]),w=w))
  253. Msg("\nAvailable utilities:")
  254. w = max([len(i) for i in utils])
  255. for cmd in sorted(utils):
  256. Msg(fs.format(cmd,utils[cmd],w=w))
  257. sys.exit()
  258. import pexpect,time,re
  259. from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file
  260. def my_send(p,t,delay=send_delay,s=False):
  261. if delay: time.sleep(delay)
  262. ret = p.send(t) # returns num bytes written
  263. if delay: time.sleep(delay)
  264. if opt.verbose:
  265. ls = "" if opt.debug or not s else " "
  266. es = "" if s else " "
  267. msg("%sSEND %s%s" % (ls,es,yellow("'%s'"%t.replace('\n',r'\n'))))
  268. return ret
  269. def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
  270. quo = "'" if type(s) == str else ""
  271. if opt.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo))
  272. else: msg_r("+")
  273. try:
  274. if s == '': ret = 0
  275. else:
  276. f = p.expect if regex else p.expect_exact
  277. ret = f(s,timeout=3)
  278. except pexpect.TIMEOUT:
  279. errmsg(red("\nERROR. Expect %s%s%s timed out. Exiting" % (quo,s,quo)))
  280. sys.exit(1)
  281. if opt.debug or (opt.verbose and type(s) != str): msg_r(" ==> %s " % ret)
  282. if ret == -1:
  283. errmsg("Error. Expect returned %s" % ret)
  284. sys.exit(1)
  285. else:
  286. if t == '':
  287. if not nonl: vmsg("")
  288. else: ret = my_send(p,t,delay,s)
  289. return ret
  290. def get_file_with_ext(ext,mydir,delete=True):
  291. flist = [os.path.join(mydir,f) for f in os.listdir(mydir)
  292. if f == ext or f[-(len(ext)+1):] == "."+ext]
  293. if not flist: return False
  294. if len(flist) > 1:
  295. if delete:
  296. if not opt.quiet:
  297. msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
  298. for f in flist: os.unlink(f)
  299. return False
  300. else:
  301. return flist[0]
  302. def get_addrfile_checksum(display=False):
  303. addrfile = get_file_with_ext("addrs",cfg['tmpdir'])
  304. silence()
  305. from mmgen.addr import AddrInfo
  306. chk = AddrInfo(addrfile).checksum
  307. if opt.verbose and display: msg("Checksum: %s" % cyan(chk))
  308. end_silence()
  309. return chk
  310. def verify_checksum_or_exit(checksum,chk):
  311. if checksum != chk:
  312. errmsg(red("Checksum error: %s" % chk))
  313. sys.exit(1)
  314. vmsg(green("Checksums match: %s") % (cyan(chk)))
  315. class MMGenExpect(object):
  316. def __init__(self,name,mmgen_cmd,cmd_args=[]):
  317. if not opt.system:
  318. mmgen_cmd = os.path.join(os.curdir,mmgen_cmd)
  319. desc = cmd_data[name][1]
  320. if opt.verbose or opt.exact_output:
  321. sys.stderr.write(
  322. green("Testing %s\nExecuting " % desc) +
  323. cyan("'%s %s'\n" % (mmgen_cmd," ".join(cmd_args)))
  324. )
  325. else:
  326. msg_r("Testing %s " % (desc+":"))
  327. if opt.direct_exec:
  328. os.system(" ".join([mmgen_cmd] + cmd_args))
  329. sys.exit()
  330. else:
  331. self.p = pexpect.spawn(mmgen_cmd,cmd_args)
  332. if opt.exact_output: self.p.logfile = sys.stdout
  333. def license(self):
  334. p = "'w' for conditions and warranty info, or 'c' to continue: "
  335. my_expect(self.p,p,'c')
  336. def usr_rand(self,num_chars):
  337. rand_chars = list(getrandstr(num_chars,no_space=True))
  338. my_expect(self.p,'symbols left: ','x')
  339. try:
  340. vmsg_r("SEND ")
  341. while self.p.expect('left: ',0.1) == 0:
  342. ch = rand_chars.pop(0)
  343. msg_r(yellow(ch)+" " if opt.verbose else "+")
  344. self.p.send(ch)
  345. except:
  346. vmsg("EOT")
  347. my_expect(self.p,"ENTER to continue: ",'\n')
  348. def passphrase_new(self,what,passphrase):
  349. my_expect(self.p,("Enter passphrase for %s: " % what), passphrase+"\n")
  350. my_expect(self.p,"Repeat passphrase: ", passphrase+"\n")
  351. def passphrase(self,what,passphrase,pwtype=""):
  352. if pwtype: pwtype += " "
  353. my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,what)),
  354. passphrase+"\n",regex=True)
  355. def hash_preset(self,what,preset=''):
  356. my_expect(self.p,("Enter hash preset for %s, or ENTER .*?:" % what),
  357. str(preset)+"\n",regex=True)
  358. def written_to_file(self,what,overwrite_unlikely=False,query="Overwrite? "):
  359. s1 = "%s written to file " % what
  360. s2 = query + "Type uppercase 'YES' to confirm: "
  361. ret = my_expect(self.p,s1 if overwrite_unlikely else [s1,s2])
  362. if ret == 1:
  363. my_send(self.p,"YES\n")
  364. ret = my_expect(self.p,s1)
  365. outfile = self.p.readline().strip().strip("'")
  366. vmsg("%s file: %s" % (what,cyan(outfile.replace("'",""))))
  367. return outfile
  368. def no_overwrite(self):
  369. self.expect("Overwrite? Type uppercase 'YES' to confirm: ","\n")
  370. self.expect("Exiting at user request")
  371. def tx_view(self):
  372. my_expect(self.p,r"View .*?transaction.*? \(y\)es, \(N\)o, pager \(v\)iew.*?: ","\n",regex=True)
  373. def expect_getend(self,s,regex=False):
  374. ret = self.expect(s,regex=regex,nonl=True)
  375. end = self.readline().strip()
  376. vmsg(" ==> %s" % cyan(end))
  377. return end
  378. def interactive(self):
  379. return self.p.interact()
  380. def logfile(self,arg):
  381. self.p.logfile = arg
  382. def expect(self,*args,**kwargs):
  383. return my_expect(self.p,*args,**kwargs)
  384. def send(self,*args,**kwargs):
  385. return my_send(self.p,*args,**kwargs)
  386. def readline(self):
  387. return self.p.readline()
  388. def readlines(self):
  389. return [l.rstrip()+"\n" for l in self.p.readlines()]
  390. def read(self,n=None):
  391. return self.p.read(n)
  392. from mmgen.rpc.data import TransactionInfo
  393. from decimal import Decimal
  394. from mmgen.bitcoin import verify_addr
  395. def add_fake_unspent_entry(out,address,comment):
  396. out.append(TransactionInfo(
  397. account = unicode(comment),
  398. vout = int(getrandnum(4) % 8),
  399. txid = unicode(hexlify(os.urandom(32))),
  400. amount = Decimal("%s.%s" % (10+(getrandnum(4) % 40), getrandnum(4) % 100000000)),
  401. address = address,
  402. spendable = False,
  403. scriptPubKey = ("76a914"+verify_addr(address,return_hex=True)+"88ac"),
  404. confirmations = getrandnum(4) % 500
  405. ))
  406. def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input=''):
  407. out = []
  408. for s in tx_data.keys():
  409. sid = tx_data[s]['sid']
  410. a = adata.addrinfo(sid)
  411. for idx,btcaddr in a.addrpairs():
  412. add_fake_unspent_entry(out,btcaddr,"%s:%s Test Wallet" % (sid,idx))
  413. if non_mmgen_input:
  414. from mmgen.bitcoin import privnum2addr,hextowif
  415. privnum = getrandnum(32)
  416. btcaddr = privnum2addr(privnum,compressed=True)
  417. of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
  418. write_to_file(of, hextowif("{:064x}".format(privnum),
  419. compressed=True)+"\n","compressed bitcoin key")
  420. add_fake_unspent_entry(out,btcaddr,"Non-MMGen address")
  421. # msg("\n".join([repr(o) for o in out])); sys.exit()
  422. write_to_file(unspent_data_file,repr(out),"Unspent outputs",verbose=True)
  423. def add_comments_to_addr_file(addrfile,tfile):
  424. silence()
  425. msg(green("Adding comments to address file '%s'" % addrfile))
  426. from mmgen.addr import AddrInfo
  427. a = AddrInfo(addrfile)
  428. for i in a.idxs(): a.set_comment(idx,"Test address %s" % idx)
  429. write_to_file(tfile,a.fmt_data(),{})
  430. end_silence()
  431. def make_brainwallet_file(fn):
  432. # Print random words with random whitespace in between
  433. from mmgen.mn_tirosh import tirosh_words
  434. wl = tirosh_words.split("\n")
  435. nwords,ws_list,max_spaces = 10," \n",5
  436. def rand_ws_seq():
  437. nchars = getrandnum(1) % max_spaces + 1
  438. return "".join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)])
  439. rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)]
  440. d = "".join(rand_pairs).rstrip() + "\n"
  441. if opt.verbose: msg_r("Brainwallet password:\n%s" % cyan(d))
  442. write_to_file(fn,d,"brainwallet password")
  443. def do_between():
  444. if opt.pause:
  445. from mmgen.util import keypress_confirm
  446. if keypress_confirm(green("Continue?"),default_yes=True):
  447. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  448. else:
  449. errmsg("Exiting at user request")
  450. sys.exit()
  451. elif opt.verbose or opt.exact_output:
  452. sys.stderr.write("\n")
  453. rebuild_list = OrderedDict()
  454. def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False):
  455. rerun = True if root else False # force_delete is not passed to recursive call
  456. fns = []
  457. if force_delete or not root:
  458. # does cmd produce a needed dependency(ies)?
  459. ret = ts.get_num_exts_for_cmd(cmd,dpy)
  460. if ret:
  461. for ext in ret[1]:
  462. fn = get_file_with_ext(ext,cfgs[ret[0]]['tmpdir'],delete=build)
  463. if fn:
  464. if force_delete: os.unlink(fn)
  465. else: fns.append(fn)
  466. else: rerun = True
  467. fdeps = ts.generate_file_deps(cmd)
  468. cdeps = ts.generate_cmd_deps(fdeps)
  469. for fn in fns:
  470. my_age = os.stat(fn).st_mtime
  471. for num,ext in fdeps:
  472. f = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
  473. if f and os.stat(f).st_mtime > my_age: rerun = True
  474. for cdep in cdeps:
  475. if check_needs_rerun(ts,cdep,build=build,root=False,dpy=cmd): rerun = True
  476. if build:
  477. if rerun:
  478. for fn in fns:
  479. if not root: os.unlink(fn)
  480. ts.do_cmd(cmd)
  481. if not root: do_between()
  482. else:
  483. # If prog produces multiple files:
  484. if cmd not in rebuild_list or rerun == True:
  485. rebuild_list[cmd] = (rerun,fns[0] if fns else "") # FIX
  486. return rerun
  487. def refcheck(what,chk,refchk):
  488. vmsg("Comparing %s '%s' to stored reference" % (what,chk))
  489. if chk == refchk:
  490. ok()
  491. else:
  492. if not opt.verbose: errmsg("")
  493. errmsg(red("""
  494. Fatal error - %s '%s' does not match reference value '%s'. Aborting test
  495. """.strip() % (what,chk,refchk)))
  496. sys.exit(3)
  497. def check_deps(cmds):
  498. if len(cmds) != 1:
  499. msg("Usage: %s check_deps <command>" % g.prog_name)
  500. sys.exit(1)
  501. cmd = cmds[0]
  502. if cmd not in cmd_data:
  503. msg("'%s': unrecognized command" % cmd)
  504. sys.exit(1)
  505. if not opt.quiet:
  506. msg("Checking dependencies for '%s'" % (cmd))
  507. check_needs_rerun(ts,cmd,build=False)
  508. w = max(len(i) for i in rebuild_list) + 1
  509. for cmd in rebuild_list:
  510. c = rebuild_list[cmd]
  511. m = "Rebuild" if (c[0] and c[1]) else "Build" if c[0] else "OK"
  512. msg("cmd {:<{w}} {}".format(cmd+":", m, w=w))
  513. # msgrepr(cmd,c)
  514. def clean(dirs=[]):
  515. ts = MMGenTestSuite()
  516. dirlist = ts.list_tmp_dirs()
  517. if not dirs: dirs = dirlist.keys()
  518. for d in sorted(dirs):
  519. if d in dirlist:
  520. cleandir(dirlist[d])
  521. else:
  522. msg("%s: invalid directory number" % d)
  523. sys.exit(1)
  524. class MMGenTestSuite(object):
  525. def __init__(self):
  526. pass
  527. def list_tmp_dirs(self):
  528. d = {}
  529. for k in cfgs: d[k] = cfgs[k]['tmpdir']
  530. return d
  531. def get_num_exts_for_cmd(self,cmd,dpy=False): # dpy ignored here
  532. num = str(cmd_data[cmd][0])
  533. dgl = cfgs[num]['dep_generators']
  534. # msgrepr(num,cmd,dgl)
  535. if cmd in dgl.values():
  536. exts = [k for k in dgl if dgl[k] == cmd]
  537. return (num,exts)
  538. else:
  539. return None
  540. def do_cmd(self,cmd):
  541. d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
  542. al = [get_file_with_ext(ext,cfgs[num]['tmpdir']) for num,ext in d]
  543. global cfg
  544. cfg = cfgs[str(cmd_data[cmd][0])]
  545. self.__class__.__dict__[cmd](*([self,cmd] + al))
  546. def generate_file_deps(self,cmd):
  547. return [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
  548. def generate_cmd_deps(self,fdeps):
  549. return [cfgs[str(n)]['dep_generators'][ext] for n,ext in fdeps]
  550. def walletgen(self,name,brain=False,seed_len=None):
  551. args = ["-d",cfg['tmpdir'],"-p1","-r10"]
  552. if seed_len: args += ["-l",str(seed_len)]
  553. # if 'seed_len' in cfg: args += ["-l",cfg['seed_len']]
  554. if brain:
  555. bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename'])
  556. args += ["-b",cfg['bw_params'],bwf]
  557. make_brainwallet_file(bwf)
  558. t = MMGenExpect(name,"mmgen-walletgen", args)
  559. t.license()
  560. if brain:
  561. t.expect(
  562. "A brainwallet will be secure only if you really know what you're doing")
  563. t.expect("Type uppercase 'YES' to confirm: ","YES\n")
  564. t.usr_rand(10)
  565. for s in "user-supplied entropy","saved user-supplied entropy":
  566. t.expect("Generating encryption key from OS random data plus %s" % s)
  567. if brain: break
  568. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  569. t.written_to_file("Wallet")
  570. ok()
  571. def refwalletgen(self,name):
  572. label = cfg['wallet_label']
  573. args = ["-d",cfg['tmpdir'],"-p1","-r10",
  574. "-b"+cfg['bw_hashparams'],"-L",label]
  575. t = MMGenExpect(name,"mmgen-walletgen", args)
  576. t.license()
  577. t.expect("Type uppercase 'YES' to confirm: ","YES\n")
  578. t.expect("passphrase: ",cfg['bw_passwd']+"\n")
  579. t.usr_rand(10)
  580. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  581. key_id = t.written_to_file("Wallet").split("-")[0].split("/")[-1]
  582. refcheck("key id",key_id,cfg['key_id'])
  583. def passchg(self,name,walletfile):
  584. t = MMGenExpect(name,"mmgen-passchg",
  585. ["-d",cfg['tmpdir'],"-p","2","-L","New Label","-r","16",walletfile])
  586. t.passphrase("MMGen wallet",cfgs['1']['wpasswd'],pwtype="old")
  587. t.expect_getend("Label changed: ")
  588. t.expect_getend("Hash preset has changed ")
  589. t.passphrase("MMGen wallet",cfg['wpasswd'],pwtype="new")
  590. t.expect("Repeat passphrase: ",cfg['wpasswd']+"\n")
  591. t.usr_rand(16)
  592. t.expect_getend("Key ID changed: ")
  593. t.written_to_file("Wallet")
  594. ok()
  595. def walletchk_newpass(self,name,walletfile):
  596. t = self.walletchk_beg(name,[walletfile])
  597. ok()
  598. def walletchk_beg(self,name,args):
  599. t = MMGenExpect(name,"mmgen-walletchk", args)
  600. t.expect("Getting MMGen wallet data from file '%s'" % args[-1])
  601. t.passphrase("MMGen wallet",cfg['wpasswd'])
  602. t.expect("Passphrase is OK")
  603. t.expect("Wallet is OK")
  604. return t
  605. def walletchk(self,name,walletfile):
  606. t = self.walletchk_beg(name,[walletfile])
  607. ok()
  608. def addrgen(self,name,walletfile,check_ref=False):
  609. t = MMGenExpect(name,"mmgen-addrgen",["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  610. t.license()
  611. t.passphrase("MMGen wallet",cfg['wpasswd'])
  612. t.expect("Passphrase is OK")
  613. t.expect("[0-9]+ addresses generated",regex=True)
  614. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  615. if check_ref:
  616. refcheck("address data checksum",chk,cfg['addrfile_chk'])
  617. return
  618. t.written_to_file("Addresses")
  619. ok()
  620. def refaddrgen(self,name,walletfile):
  621. self.addrgen(name,walletfile,check_ref=True)
  622. def addrimport(self,name,addrfile):
  623. outfile = os.path.join(cfg['tmpdir'],"addrfile_w_comments")
  624. add_comments_to_addr_file(addrfile,outfile)
  625. t = MMGenExpect(name,"mmgen-addrimport",[outfile])
  626. t.expect_getend(r"checksum for addr data .*\[.*\]: ",regex=True)
  627. t.expect_getend("Validating addresses...OK. ")
  628. t.expect("Type uppercase 'YES' to confirm: ","\n")
  629. vmsg("This is a simulation, so no addresses were actually imported into the tracking\nwallet")
  630. ok()
  631. def txcreate(self,name,addrfile):
  632. self.txcreate_common(name,sources=['1'])
  633. def txcreate_common(self,name,sources=['1'],non_mmgen_input=''):
  634. if opt.verbose or opt.exact_output:
  635. sys.stderr.write(green("Generating fake transaction info\n"))
  636. silence()
  637. from mmgen.addr import AddrInfo,AddrInfoList
  638. tx_data,ail = {},AddrInfoList()
  639. from mmgen.util import parse_addr_idxs
  640. for s in sources:
  641. afile = get_file_with_ext("addrs",cfgs[s]["tmpdir"])
  642. ai = AddrInfo(afile)
  643. ail.add(ai)
  644. aix = parse_addr_idxs(cfgs[s]['addr_idx_list'])
  645. if len(aix) != addrs_per_wallet:
  646. errmsg(red("Addr index list length != %s: %s" %
  647. (addrs_per_wallet,repr(aix))))
  648. sys.exit()
  649. tx_data[s] = {
  650. 'addrfile': afile,
  651. 'chk': ai.checksum,
  652. 'sid': ai.seed_id,
  653. 'addr_idxs': aix[-2:],
  654. }
  655. unspent_data_file = os.path.join(cfg['tmpdir'],"unspent.json")
  656. create_fake_unspent_data(ail,unspent_data_file,tx_data,non_mmgen_input)
  657. # make the command line
  658. from mmgen.bitcoin import privnum2addr
  659. btcaddr = privnum2addr(getrandnum(32),compressed=True)
  660. cmd_args = ["-d",cfg['tmpdir']]
  661. for num in tx_data.keys():
  662. s = tx_data[num]
  663. cmd_args += [
  664. "%s:%s,%s" % (s['sid'],s['addr_idxs'][0],cfgs[num]['amts'][0]),
  665. ]
  666. # + one BTC address
  667. # + one change address and one BTC address
  668. if num is tx_data.keys()[-1]:
  669. cmd_args += ["%s:%s" % (s['sid'],s['addr_idxs'][1])]
  670. cmd_args += ["%s,%s" % (btcaddr,cfgs[num]['amts'][1])]
  671. for num in tx_data: cmd_args += [tx_data[num]['addrfile']]
  672. os.environ["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file
  673. end_silence()
  674. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  675. t = MMGenExpect(name,"mmgen-txcreate",cmd_args)
  676. t.license()
  677. for num in tx_data.keys():
  678. t.expect_getend("Getting address data from file ")
  679. chk=t.expect_getend(r"Computed checksum for addr data .*?: ",regex=True)
  680. verify_checksum_or_exit(tx_data[num]['chk'],chk)
  681. # not in tracking wallet warning, (1 + num sources) times
  682. if t.expect(["Continue anyway? (y/N): ",
  683. "Unable to connect to bitcoind"]) == 0:
  684. t.send("y")
  685. else:
  686. errmsg(red("Error: unable to connect to bitcoind. Exiting"))
  687. sys.exit(1)
  688. for num in tx_data.keys():
  689. t.expect("Continue anyway? (y/N): ","y")
  690. t.expect(r"'q' = quit sorting, .*?: ","M", regex=True)
  691. t.expect(r"'q' = quit sorting, .*?: ","q", regex=True)
  692. outputs_list = [addrs_per_wallet*i + 1 for i in range(len(tx_data))]
  693. if non_mmgen_input: outputs_list.append(len(tx_data)*addrs_per_wallet + 1)
  694. t.expect("Enter a range or space-separated list of outputs to spend: ",
  695. " ".join([str(i) for i in outputs_list])+"\n")
  696. if non_mmgen_input: t.expect("Accept? (y/N): ","y")
  697. t.expect("OK? (Y/n): ","y")
  698. t.expect("Add a comment to transaction? (y/N): ","\n")
  699. t.tx_view()
  700. t.expect("Save transaction? (y/N): ","y")
  701. t.written_to_file("Transaction")
  702. ok()
  703. def txsign(self,name,txfile,walletfile):
  704. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txfile,walletfile])
  705. t.license()
  706. t.tx_view()
  707. t.passphrase("MMGen wallet",cfg['wpasswd'])
  708. t.expect("Edit transaction comment? (y/N): ","\n")
  709. t.written_to_file("Signed transaction")
  710. ok()
  711. def txsend(self,name,sigfile):
  712. t = MMGenExpect(name,"mmgen-txsend", ["-d",cfg['tmpdir'],sigfile])
  713. t.license()
  714. t.tx_view()
  715. t.expect("Edit transaction comment? (y/N): ","\n")
  716. t.expect("Are you sure you want to broadcast this transaction to the network?")
  717. t.expect("Type uppercase 'YES, I REALLY WANT TO DO THIS' to confirm: ","\n")
  718. t.expect("Exiting at user request")
  719. vmsg("This is a simulation, so no transaction was sent")
  720. ok()
  721. def export_seed(self,name,walletfile):
  722. t = self.walletchk_beg(name,["-s","-d",cfg['tmpdir'],walletfile])
  723. f = t.written_to_file("Seed data")
  724. silence()
  725. msg("Seed data: %s" % cyan(get_data_from_file(f,"seed data")))
  726. end_silence()
  727. ok()
  728. def export_mnemonic(self,name,walletfile):
  729. t = self.walletchk_beg(name,["-m","-d",cfg['tmpdir'],walletfile])
  730. f = t.written_to_file("Mnemonic data")
  731. silence()
  732. msg_r("Mnemonic data: %s" % cyan(get_data_from_file(f,"mnemonic data")))
  733. end_silence()
  734. ok()
  735. def export_incog(self,name,walletfile,args=["-g"]):
  736. t = MMGenExpect(name,"mmgen-walletchk",args+["-d",cfg['tmpdir'],"-r","10",walletfile])
  737. t.passphrase("MMGen wallet",cfg['wpasswd'])
  738. t.usr_rand(10)
  739. incog_id = t.expect_getend("Incog ID: ")
  740. write_to_tmpfile(cfg,incog_id_fn,incog_id+"\n")
  741. if args[0] == "-G": return t
  742. t.written_to_file("Incognito wallet data",overwrite_unlikely=True)
  743. ok()
  744. def export_incog_hex(self,name,walletfile):
  745. self.export_incog(name,walletfile,args=["-X"])
  746. # TODO: make outdir and hidden incog compatible (ignore --outdir and warn user?)
  747. def export_incog_hidden(self,name,walletfile):
  748. rf,rd = os.path.join(cfg['tmpdir'],hincog_fn),os.urandom(hincog_bytes)
  749. vmsg(green("Writing %s bytes of data to file '%s'" % (hincog_bytes,rf)))
  750. write_to_file(rf,rd,verbose=opt.verbose)
  751. t = self.export_incog(name,walletfile,args=["-G","%s,%s"%(rf,hincog_offset)])
  752. t.written_to_file("Data",query="")
  753. ok()
  754. def addrgen_seed(self,name,walletfile,foo,what="seed data",arg="-s"):
  755. t = MMGenExpect(name,"mmgen-addrgen",
  756. [arg,"-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  757. t.license()
  758. t.expect_getend("Valid %s for seed ID " % what)
  759. vmsg("Comparing generated checksum with checksum from previous address file")
  760. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  761. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  762. t.no_overwrite()
  763. ok()
  764. def addrgen_mnemonic(self,name,walletfile,foo):
  765. self.addrgen_seed(name,walletfile,foo,what="mnemonic",arg="-m")
  766. def addrgen_incog(self,name,walletfile,foo,args=["-g"]):
  767. t = MMGenExpect(name,"mmgen-addrgen",args+["-d",
  768. cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  769. t.license()
  770. t.expect_getend("Incog ID: ")
  771. t.passphrase("MMGen incognito wallet \w{8}", cfg['wpasswd'])
  772. t.hash_preset("incog wallet",'1')
  773. vmsg("Comparing generated checksum with checksum from address file")
  774. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  775. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  776. t.no_overwrite()
  777. ok()
  778. def addrgen_incog_hex(self,name,walletfile,foo):
  779. self.addrgen_incog(name,walletfile,foo,args=["-X"])
  780. def addrgen_incog_hidden(self,name,walletfile,foo):
  781. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  782. self.addrgen_incog(name,walletfile,foo,
  783. args=["-G","%s,%s,%s"%(rf,hincog_offset,hincog_seedlen)])
  784. def keyaddrgen(self,name,walletfile,check_ref=False):
  785. t = MMGenExpect(name,"mmgen-keygen",
  786. ["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  787. t.license()
  788. t.expect("Type uppercase 'YES' to confirm: ","YES\n")
  789. t.passphrase("MMGen wallet",cfg['wpasswd'])
  790. chk = t.expect_getend(r"Checksum for key-address data .*?: ",regex=True)
  791. if check_ref:
  792. refcheck("key-address data checksum",chk,cfg['keyaddrfile_chk'])
  793. return
  794. t.expect("Encrypt key list? (y/N): ","y")
  795. t.hash_preset("new key list",'1')
  796. t.passphrase_new("new key list",cfg['kapasswd'])
  797. t.written_to_file("Keys")
  798. ok()
  799. def refkeyaddrgen(self,name,walletfile):
  800. self.keyaddrgen(name,walletfile,check_ref=True)
  801. def txsign_keyaddr(self,name,keyaddr_file,txfile):
  802. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],"-M",keyaddr_file,txfile])
  803. t.license()
  804. t.hash_preset("key-address file",'1')
  805. t.passphrase("key-address file",cfg['kapasswd'])
  806. t.expect("Check key-to-address validity? (y/N): ","y")
  807. t.tx_view()
  808. t.expect("Signing transaction...OK")
  809. t.expect("Edit transaction comment? (y/N): ","\n")
  810. t.written_to_file("Signed transaction")
  811. ok()
  812. def walletgen2(self,name):
  813. self.walletgen(name,seed_len=128)
  814. def addrgen2(self,name,walletfile):
  815. self.addrgen(name,walletfile)
  816. def txcreate2(self,name,addrfile):
  817. self.txcreate_common(name,sources=['2'])
  818. def txsign2(self,name,txf1,wf1,txf2,wf2):
  819. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txf1,wf1,txf2,wf2])
  820. t.license()
  821. for cnum in ['1','2']:
  822. t.tx_view()
  823. t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd'])
  824. t.expect_getend("Signing transaction ")
  825. t.expect("Edit transaction comment? (y/N): ","\n")
  826. t.written_to_file("Signed transaction #%s" % cnum)
  827. ok()
  828. def export_mnemonic2(self,name,walletfile):
  829. self.export_mnemonic(name,walletfile)
  830. def walletgen3(self,name):
  831. self.walletgen(name)
  832. def addrgen3(self,name,walletfile):
  833. self.addrgen(name,walletfile)
  834. def txcreate3(self,name,addrfile1,addrfile2):
  835. self.txcreate_common(name,sources=['1','3'])
  836. def txsign3(self,name,wf1,wf2,txf2):
  837. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],wf1,wf2,txf2])
  838. t.license()
  839. t.tx_view()
  840. for s in ['1','3']:
  841. t.expect_getend("Getting MMGen wallet data from file ")
  842. t.passphrase("MMGen wallet",cfgs[s]['wpasswd'])
  843. t.expect_getend("Signing transaction")
  844. t.expect("Edit transaction comment? (y/N): ","\n")
  845. t.written_to_file("Signed transaction")
  846. ok()
  847. def walletgen4(self,name):
  848. self.walletgen(name,brain=True)
  849. def addrgen4(self,name,walletfile):
  850. self.addrgen(name,walletfile)
  851. def txcreate4(self,name,f1,f2,f3,f4):
  852. self.txcreate_common(name,sources=['1','2','3','4'],non_mmgen_input='4')
  853. def txsign4(self,name,f1,f2,f3,f4,f5):
  854. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  855. t = MMGenExpect(name,"mmgen-txsign",
  856. ["-d",cfg['tmpdir'],"-b",cfg['bw_params'],"-k",non_mm_fn,f1,f2,f3,f4,f5])
  857. t.license()
  858. t.tx_view()
  859. for cfgnum,what,app in ('1',"incognito"," incognito"),('3',"MMGen",""):
  860. t.expect_getend("Getting %s wallet data from file " % what)
  861. t.passphrase("MMGen%s wallet"%app,cfgs[cfgnum]['wpasswd'])
  862. if cfgnum == '1':
  863. t.hash_preset("incog wallet",'1')
  864. t.expect_getend("Signing transaction")
  865. t.expect("Edit transaction comment? (y/N): ","\n")
  866. t.written_to_file("Signed transaction")
  867. ok()
  868. def tool_encrypt(self,name,infile=""):
  869. if infile:
  870. infn = infile
  871. else:
  872. d = os.urandom(1033)
  873. tmp_fn = cfg['tool_enc_infn']
  874. write_to_tmpfile(cfg,tmp_fn,d)
  875. infn = get_tmpfile_fn(cfg,tmp_fn)
  876. t = MMGenExpect(name,"mmgen-tool",["-d",cfg['tmpdir'],"encrypt",infn])
  877. t.hash_preset("user data",'1')
  878. t.passphrase_new("user data",cfg['tool_enc_passwd'])
  879. t.written_to_file("Encrypted data")
  880. ok()
  881. def tool_encrypt_ref(self,name):
  882. infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn'])
  883. write_to_file(infn,cfg['tool_enc_reftext'],silent=True)
  884. self.tool_encrypt(name,infn)
  885. def tool_decrypt(self,name,f1,f2):
  886. of = name + ".out"
  887. t = MMGenExpect(name,"mmgen-tool",
  888. ["-d",cfg['tmpdir'],"decrypt",f2,"outfile="+of,"hash_preset=1"])
  889. t.passphrase("user data",cfg['tool_enc_passwd'])
  890. t.written_to_file("Decrypted data")
  891. d1 = read_from_file(f1)
  892. d2 = read_from_file(get_tmpfile_fn(cfg,of))
  893. cmp_or_die(d1,d2)
  894. def tool_decrypt_ref(self,name,f1,f2):
  895. self.tool_decrypt(name,f1,f2)
  896. def tool_find_incog_data(self,name,f1,f2):
  897. i_id = read_from_file(f2).rstrip()
  898. vmsg("Incog ID: %s" % cyan(i_id))
  899. t = MMGenExpect(name,"mmgen-tool",
  900. ["-d",cfg['tmpdir'],"find_incog_data",f1,i_id])
  901. o = t.expect_getend("Incog data for ID \w{8} found at offset ",regex=True)
  902. cmp_or_die(hincog_offset,int(o))
  903. # main()
  904. if opt.pause:
  905. import termios,atexit
  906. fd = sys.stdin.fileno()
  907. old = termios.tcgetattr(fd)
  908. def at_exit():
  909. termios.tcsetattr(fd, termios.TCSADRAIN, old)
  910. atexit.register(at_exit)
  911. start_time = int(time.time())
  912. ts = MMGenTestSuite()
  913. for cfg in sorted(cfgs): mk_tmpdir(cfgs[cfg])
  914. try:
  915. if cmd_args:
  916. arg1 = cmd_args[0]
  917. if arg1 in utils:
  918. globals()[arg1](cmd_args[1:])
  919. sys.exit()
  920. elif arg1 in meta_cmds:
  921. if len(cmd_args) == 1:
  922. for cmd in meta_cmds[arg1][1]:
  923. check_needs_rerun(ts,cmd,build=True,force_delete=True)
  924. else:
  925. msg("Only one meta command may be specified")
  926. sys.exit(1)
  927. elif arg1 in cmd_data.keys():
  928. if len(cmd_args) == 1:
  929. check_needs_rerun(ts,arg1,build=True)
  930. else:
  931. msg("Only one command may be specified")
  932. sys.exit(1)
  933. else:
  934. errmsg("%s: unrecognized command" % arg1)
  935. sys.exit(1)
  936. else:
  937. clean()
  938. for cmd in cmd_data:
  939. ts.do_cmd(cmd)
  940. if cmd is not cmd_data.keys()[-1]: do_between()
  941. except:
  942. sys.stderr = stderr_save
  943. raise
  944. t = int(time.time()) - start_time
  945. sys.stderr.write(green(
  946. "All requested tests finished OK, elapsed time: %02i:%02i\n"
  947. % (t/60,t%60)))