test.py 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550
  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.globalvars as g
  10. import mmgen.opt as opt
  11. from mmgen.util import mmsg,mdie,Msg,die,capfirst
  12. from mmgen.test import *
  13. tb_cmd = "scripts/traceback.py"
  14. hincog_fn = "rand_data"
  15. hincog_bytes = 1024*1024
  16. hincog_offset = 98765
  17. hincog_seedlen = 256
  18. incog_id_fn = "incog_id"
  19. non_mmgen_fn = "btckey"
  20. ref_dir = os.path.join("test","ref")
  21. ref_wallet_brainpass = "abc"
  22. ref_wallet_hash_preset = "1"
  23. ref_wallet_incog_offset = 123
  24. ref_bw_hash_preset = "1"
  25. ref_bw_file = "wallet.mmbrain"
  26. ref_bw_file_spc = "wallet-spaced.mmbrain"
  27. ref_kafile_pass = "kafile password"
  28. ref_kafile_hash_preset = "1"
  29. ref_enc_fn = "sample-text.mmenc"
  30. tool_enc_passwd = "Scrypt it, don't hash it!"
  31. sample_text = \
  32. "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n"
  33. cfgs = {
  34. '6': {
  35. 'name': "reference wallet check (128-bit)",
  36. 'seed_len': 128,
  37. 'seed_id': "FE3C6545",
  38. 'ref_bw_seed_id': "33F10310",
  39. 'addrfile_chk': "B230 7526 638F 38CB 8FDC 8B76",
  40. 'keyaddrfile_chk': "CF83 32FB 8A8B 08E2 0F00 D601",
  41. 'wpasswd': "reference password",
  42. 'ref_wallet': "FE3C6545-D782B529[128,1].mmdat",
  43. 'ic_wallet': "FE3C6545-E29303EA-5E229E30[128,1].mmincog",
  44. 'ic_wallet_hex': "FE3C6545-BC4BE3F2-32586837[128,1].mmincox",
  45. 'hic_wallet': "FE3C6545-161E495F-BEB7548E[128:1].incog-offset123",
  46. 'hic_wallet_old': "FE3C6545-161E495F-9860A85B[128:1].incog-old.offset123",
  47. 'tmpdir': os.path.join("test","tmp6"),
  48. 'kapasswd': "",
  49. 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses
  50. 'dep_generators': {
  51. 'mmdat': "refwalletgen1",
  52. 'addrs': "refaddrgen1",
  53. 'akeys.mmenc': "refkeyaddrgen1"
  54. },
  55. },
  56. '7': {
  57. 'name': "reference wallet check (192-bit)",
  58. 'seed_len': 192,
  59. 'seed_id': "1378FC64",
  60. 'ref_bw_seed_id': "CE918388",
  61. 'addrfile_chk': "8C17 A5FA 0470 6E89 3A87 8182",
  62. 'keyaddrfile_chk': "9648 5132 B98E 3AD9 6FC3 C5AD",
  63. 'wpasswd': "reference password",
  64. 'ref_wallet': "1378FC64-6F0F9BB4[192,1].mmdat",
  65. 'ic_wallet': "1378FC64-2907DE97-F980D21F[192,1].mmincog",
  66. 'ic_wallet_hex': "1378FC64-4DCB5174-872806A7[192,1].mmincox",
  67. 'hic_wallet': "1378FC64-B55E9958-77256FC1[192:1].incog.offset123",
  68. 'hic_wallet_old': "1378FC64-B55E9958-D85FF20C[192:1].incog-old.offset123",
  69. 'tmpdir': os.path.join("test","tmp7"),
  70. 'kapasswd': "",
  71. 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses
  72. 'dep_generators': {
  73. 'mmdat': "refwalletgen2",
  74. 'addrs': "refaddrgen2",
  75. 'akeys.mmenc': "refkeyaddrgen2"
  76. },
  77. },
  78. '8': {
  79. 'name': "reference wallet check (256-bit)",
  80. 'seed_len': 256,
  81. 'seed_id': "98831F3A",
  82. 'ref_bw_seed_id': "B48CD7FC",
  83. 'addrfile_chk': "6FEF 6FB9 7B13 5D91 854A 0BD3",
  84. 'keyaddrfile_chk': "9F2D D781 1812 8BAD C396 9DEB",
  85. 'wpasswd': "reference password",
  86. 'ref_wallet': "98831F3A-27F2BF93[256,1].mmdat",
  87. 'ref_addrfile': "98831F3A[1,31-33,500-501,1010-1011].addrs",
  88. 'ref_keyaddrfile': "98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc",
  89. 'ref_addrfile_chksum': "6FEF 6FB9 7B13 5D91 854A 0BD3",
  90. 'ref_keyaddrfile_chksum': "9F2D D781 1812 8BAD C396 9DEB",
  91. # 'ref_fake_unspent_data':"98831F3A_unspent.json",
  92. 'ref_tx_file': "tx_FFB367[1.234].raw",
  93. 'ic_wallet': "98831F3A-5482381C-18460FB1[256,1].mmincog",
  94. 'ic_wallet_hex': "98831F3A-1630A9F2-870376A9[256,1].mmincox",
  95. 'hic_wallet': "98831F3A-F59B07A0-559CEF19[256:1].incog.offset123",
  96. 'hic_wallet_old': "98831F3A-F59B07A0-848535F3[256:1].incog-old.offset123",
  97. 'tmpdir': os.path.join("test","tmp8"),
  98. 'kapasswd': "",
  99. 'addr_idx_list': "1010,500-501,31-33,1,33,500,1011", # 8 addresses
  100. 'dep_generators': {
  101. 'mmdat': "refwalletgen3",
  102. 'addrs': "refaddrgen3",
  103. 'akeys.mmenc': "refkeyaddrgen3"
  104. },
  105. },
  106. '1': {
  107. 'tmpdir': os.path.join("test","tmp1"),
  108. 'wpasswd': "Dorian",
  109. 'kapasswd': "Grok the blockchain",
  110. 'addr_idx_list': "12,99,5-10,5,12", # 8 addresses
  111. 'dep_generators': {
  112. 'mmdat': "walletgen",
  113. 'addrs': "addrgen",
  114. 'raw': "txcreate",
  115. 'sig': "txsign",
  116. 'mmwords': "export_mnemonic",
  117. 'mmseed': "export_seed",
  118. 'mmincog': "export_incog",
  119. 'mmincox': "export_incog_hex",
  120. hincog_fn: "export_incog_hidden",
  121. incog_id_fn: "export_incog_hidden",
  122. 'akeys.mmenc': "keyaddrgen"
  123. },
  124. },
  125. '2': {
  126. 'tmpdir': os.path.join("test","tmp2"),
  127. 'wpasswd': "Hodling away",
  128. 'addr_idx_list': "37,45,3-6,22-23", # 8 addresses
  129. 'seed_len': 128,
  130. 'dep_generators': {
  131. 'mmdat': "walletgen2",
  132. 'addrs': "addrgen2",
  133. 'raw': "txcreate2",
  134. 'sig': "txsign2",
  135. 'mmwords': "export_mnemonic2",
  136. },
  137. },
  138. '3': {
  139. 'tmpdir': os.path.join("test","tmp3"),
  140. 'wpasswd': "Major miner",
  141. 'addr_idx_list': "73,54,1022-1023,2-5", # 8 addresses
  142. 'dep_generators': {
  143. 'mmdat': "walletgen3",
  144. 'addrs': "addrgen3",
  145. 'raw': "txcreate3",
  146. 'sig': "txsign3"
  147. },
  148. },
  149. '4': {
  150. 'tmpdir': os.path.join("test","tmp4"),
  151. 'wpasswd': "Hashrate rising",
  152. 'addr_idx_list': "63,1004,542-544,7-9", # 8 addresses
  153. 'seed_len': 192,
  154. 'dep_generators': {
  155. 'mmdat': "walletgen4",
  156. 'mmbrain': "walletgen4",
  157. 'addrs': "addrgen4",
  158. 'raw': "txcreate4",
  159. 'sig': "txsign4",
  160. },
  161. 'bw_filename': "brainwallet.mmbrain",
  162. 'bw_params': "192,1",
  163. },
  164. '5': {
  165. 'tmpdir': os.path.join("test","tmp5"),
  166. 'wpasswd': "My changed password",
  167. 'dep_generators': {
  168. 'mmdat': "passchg",
  169. },
  170. },
  171. '9': {
  172. 'tmpdir': os.path.join("test","tmp9"),
  173. 'tool_enc_infn': "tool_encrypt.in",
  174. # 'tool_enc_ref_infn': "tool_encrypt_ref.in",
  175. 'dep_generators': {
  176. 'tool_encrypt.in': "tool_encrypt",
  177. 'tool_encrypt.in.mmenc': "tool_encrypt",
  178. # 'tool_encrypt_ref.in': "tool_encrypt_ref",
  179. # 'tool_encrypt_ref.in.mmenc': "tool_encrypt_ref",
  180. },
  181. },
  182. }
  183. from copy import deepcopy
  184. for a,b in ('6','11'),('7','12'),('8','13'):
  185. cfgs[b] = deepcopy(cfgs[a])
  186. cfgs[b]['tmpdir'] = os.path.join("test","tmp"+b)
  187. from collections import OrderedDict
  188. cmd_data = OrderedDict([
  189. # test description depends
  190. ['walletgen', (1,'wallet generation', [[[],1]])],
  191. # ['walletchk', (1,'wallet check', [[["mmdat"],1]])],
  192. ['passchg', (5,'password, label and hash preset change',[[["mmdat"],1]])],
  193. ['walletchk_newpass',(5,'wallet check with new pw, label and hash preset',[[["mmdat"],5]])],
  194. ['addrgen', (1,'address generation', [[["mmdat"],1]])],
  195. ['addrimport', (1,'address import', [[["addrs"],1]])],
  196. ['txcreate', (1,'transaction creation', [[["addrs"],1]])],
  197. ['txsign', (1,'transaction signing', [[["mmdat","raw"],1]])],
  198. ['txsend', (1,'transaction sending', [[["sig"],1]])],
  199. ['export_seed', (1,'seed export to mmseed format', [[["mmdat"],1]])],
  200. ['export_mnemonic', (1,'seed export to mmwords format', [[["mmdat"],1]])],
  201. ['export_incog', (1,'seed export to mmincog format', [[["mmdat"],1]])],
  202. ['export_incog_hex',(1,'seed export to mmincog hex format', [[["mmdat"],1]])],
  203. ['export_incog_hidden',(1,'seed export to hidden mmincog format', [[["mmdat"],1]])],
  204. ['addrgen_seed', (1,'address generation from mmseed file', [[["mmseed","addrs"],1]])],
  205. ['addrgen_mnemonic',(1,'address generation from mmwords file',[[["mmwords","addrs"],1]])],
  206. ['addrgen_incog', (1,'address generation from mmincog file',[[["mmincog","addrs"],1]])],
  207. ['addrgen_incog_hex',(1,'address generation from mmincog hex file',[[["mmincox","addrs"],1]])],
  208. ['addrgen_incog_hidden',(1,'address generation from hidden mmincog file', [[[hincog_fn,"addrs"],1]])],
  209. ['keyaddrgen', (1,'key-address file generation', [[["mmdat"],1]])],
  210. ['txsign_keyaddr',(1,'transaction signing with key-address file', [[["akeys.mmenc","raw"],1]])],
  211. ['walletgen2',(2,'wallet generation (2), 128-bit seed', [])],
  212. ['addrgen2', (2,'address generation (2)', [[["mmdat"],2]])],
  213. ['txcreate2', (2,'transaction creation (2)', [[["addrs"],2]])],
  214. ['txsign2', (2,'transaction signing, two transactions',[[["mmdat","raw"],1],[["mmdat","raw"],2]])],
  215. ['export_mnemonic2', (2,'seed export to mmwords format (2)',[[["mmdat"],2]])],
  216. ['walletgen3',(3,'wallet generation (3)', [])],
  217. ['addrgen3', (3,'address generation (3)', [[["mmdat"],3]])],
  218. ['txcreate3', (3,'tx creation with inputs and outputs from two wallets', [[["addrs"],1],[["addrs"],3]])],
  219. ['txsign3', (3,'tx signing with inputs and outputs from two wallets',[[["mmdat"],1],[["mmdat","raw"],3]])],
  220. ['walletgen4',(4,'wallet generation (4) (brainwallet)', [])],
  221. ['addrgen4', (4,'address generation (4)', [[["mmdat"],4]])],
  222. ['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]])],
  223. ['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]])],
  224. ['tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [])],
  225. ['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)", [[[cfgs['9']['tool_enc_infn'],cfgs['9']['tool_enc_infn']+".mmenc"],9]])],
  226. # ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])],
  227. ['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])],
  228. ])
  229. # saved reference data
  230. cmd_data_ref = (
  231. # reading
  232. ('ref_wallet_chk', ([],'saved reference wallet')),
  233. ('ref_seed_chk', ([],'saved seed file')),
  234. ('ref_mn_chk', ([],'saved mnemonic file')),
  235. ('ref_hincog_chk', ([],'saved hidden incog reference wallet')),
  236. ('ref_brain_chk', ([],'saved brainwallet')),
  237. # generating new reference ('abc' brainwallet) files:
  238. ('refwalletgen', ([],'gen new refwallet')),
  239. ('refaddrgen', (["mmdat"],'new refwallet addr chksum')),
  240. ('refkeyaddrgen', (["mmdat"],'new refwallet key-addr chksum'))
  241. )
  242. # misc. saved reference data
  243. cmd_data_ref_other = (
  244. ('ref_addrfile_chk', 'saved reference address file'),
  245. ('ref_keyaddrfile_chk','saved reference key-address file'),
  246. # Create the fake inputs:
  247. # ('txcreate8', 'transaction creation (8)'),
  248. ('ref_tx_chk', 'saved reference tx file'),
  249. ('ref_brain_chk_spc3', 'saved brainwallet (non-standard spacing)'),
  250. ('ref_tool_decrypt', 'decryption of saved MMGen-encrypted file'),
  251. )
  252. # mmgen-walletconv:
  253. cmd_data_conv_in = ( # reading
  254. ('ref_wallet_conv', 'conversion of saved reference wallet'),
  255. ('ref_mn_conv', 'conversion of saved mnemonic'),
  256. ('ref_seed_conv', 'conversion of saved seed file'),
  257. ('ref_brain_conv', 'conversion of ref brainwallet'),
  258. ('ref_incog_conv', 'conversion of saved incog wallet'),
  259. ('ref_incox_conv', 'conversion of saved hex incog wallet'),
  260. ('ref_hincog_conv', 'conversion of saved hidden incog wallet'),
  261. ('ref_hincog_conv_old','conversion of saved hidden incog wallet (old format)')
  262. )
  263. cmd_data_conv_out = ( # writing
  264. ('ref_wallet_conv_out', 'ref seed conversion to wallet'),
  265. ('ref_mn_conv_out', 'ref seed conversion to mnemonic'),
  266. ('ref_seed_conv_out', 'ref seed conversion to seed'),
  267. ('ref_incog_conv_out', 'ref seed conversion to incog data'),
  268. ('ref_incox_conv_out', 'ref seed conversion to hex incog data'),
  269. ('ref_hincog_conv_out', 'ref seed conversion to hidden incog data')
  270. )
  271. cmd_groups = OrderedDict([
  272. ('main', cmd_data.keys()),
  273. ('ref', [c[0]+str(i) for c in cmd_data_ref for i in (1,2,3)]),
  274. ('ref_other', [c[0] for c in cmd_data_ref_other]),
  275. ('conv_in', [c[0]+str(i) for c in cmd_data_conv_in for i in (1,2,3)]),
  276. ('conv_out', [c[0]+str(i) for c in cmd_data_conv_out for i in (1,2,3)]),
  277. ])
  278. for a,b in cmd_data_ref:
  279. for i,j in (1,128),(2,192),(3,256):
  280. cmd_data[a+str(i)] = (5+i,"%s (%s-bit)" % (b[1],j),[[b[0],5+i]])
  281. for a,b in cmd_data_ref_other:
  282. cmd_data[a] = (8,b,[[[],8]])
  283. for a,b in cmd_data_conv_in:
  284. for i,j in (1,128),(2,192),(3,256):
  285. cmd_data[a+str(i)] = (10+i,"%s (%s-bit)" % (b,j),[[[],10+i]])
  286. for a,b in cmd_data_conv_out:
  287. for i,j in (1,128),(2,192),(3,256):
  288. cmd_data[a+str(i)] = (10+i,"%s (%s-bit)" % (b,j),[[[],10+i]])
  289. utils = {
  290. 'check_deps': 'check dependencies for specified command',
  291. 'clean': 'clean specified tmp dir(s) 1,2,3,4,5 or 6 (no arg = all dirs)',
  292. }
  293. addrs_per_wallet = 8
  294. # total of two outputs must be < 10 BTC
  295. for k in cfgs.keys():
  296. cfgs[k]['amts'] = [0,0]
  297. for idx,mod in (0,6),(1,4):
  298. cfgs[k]['amts'][idx] = "%s.%s" % ((getrandnum(2) % mod), str(getrandnum(4))[:5])
  299. meta_cmds = OrderedDict([
  300. ['ref1', ("refwalletgen1","refaddrgen1","refkeyaddrgen1")],
  301. ['ref2', ("refwalletgen2","refaddrgen2","refkeyaddrgen2")],
  302. ['ref3', ("refwalletgen3","refaddrgen3","refkeyaddrgen3")],
  303. ['gen', ("walletgen","addrgen")],
  304. ['pass', ("passchg","walletchk_newpass")],
  305. ['tx', ("addrimport","txcreate","txsign","txsend")],
  306. ['export', [k for k in cmd_data if k[:7] == "export_" and cmd_data[k][0] == 1]],
  307. ['gen_sp', [k for k in cmd_data if k[:8] == "addrgen_" and cmd_data[k][0] == 1]],
  308. ['online', ("keyaddrgen","txsign_keyaddr")],
  309. ['2', [k for k in cmd_data if cmd_data[k][0] == 2]],
  310. ['3', [k for k in cmd_data if cmd_data[k][0] == 3]],
  311. ['4', [k for k in cmd_data if cmd_data[k][0] == 4]],
  312. ['tool', ("tool_encrypt","tool_decrypt","tool_find_incog_data")],
  313. ['saved_ref1', [c[0]+"1" for c in cmd_data_ref]],
  314. ['saved_ref2', [c[0]+"2" for c in cmd_data_ref]],
  315. ['saved_ref3', [c[0]+"3" for c in cmd_data_ref]],
  316. ['saved_ref_other', [c[0] for c in cmd_data_ref_other]],
  317. ['saved_ref_conv_in1', [c[0]+"1" for c in cmd_data_conv_in]],
  318. ['saved_ref_conv_in2', [c[0]+"2" for c in cmd_data_conv_in]],
  319. ['saved_ref_conv_in3', [c[0]+"3" for c in cmd_data_conv_in]],
  320. ['saved_ref_conv_out1', [c[0]+"1" for c in cmd_data_conv_out]],
  321. ['saved_ref_conv_out2', [c[0]+"2" for c in cmd_data_conv_out]],
  322. ['saved_ref_conv_out3', [c[0]+"3" for c in cmd_data_conv_out]],
  323. ])
  324. opts_data = {
  325. 'desc': "Test suite for the MMGen suite",
  326. 'usage':"[options] [command(s) or metacommand(s)]",
  327. 'options': """
  328. -h, --help Print this help message
  329. -b, --buf-keypress Use buffered keypresses as with real human input
  330. -d, --debug-scripts Turn on debugging output in executed scripts
  331. -D, --direct-exec Bypass pexpect and execute a command directly (for
  332. debugging only)
  333. -e, --exact-output Show the exact output of the MMGen script(s) being run
  334. -l, --list-cmds List and describe the tests and commands in the test suite
  335. -n, --names Display command names instead of descriptions
  336. -p, --pause Pause between tests, resuming on keypress
  337. -q, --quiet Produce minimal output. Suppress dependency info
  338. -s, --system Test scripts and modules installed on system rather than
  339. those in the repo root
  340. -t, --traceback Run the command inside the '{tb_cmd}' script
  341. -v, --verbose Produce more verbose output
  342. """.format(tb_cmd=tb_cmd),
  343. 'notes': """
  344. If no command is given, the whole suite of tests is run.
  345. """
  346. }
  347. cmd_args = opt.opts.init(opts_data)
  348. if opt.system: sys.path.pop(0)
  349. # temporary
  350. #os.environ["MMGEN_USE_OLD_SCRIPTS"] = "1"
  351. if opt.debug_scripts: os.environ["MMGEN_DEBUG"] = "1"
  352. if opt.buf_keypress:
  353. send_delay = 0.3
  354. else:
  355. send_delay = 0
  356. os.environ["MMGEN_DISABLE_HOLD_PROTECT"] = "1"
  357. if opt.exact_output:
  358. def msg(s): pass
  359. vmsg = vmsg_r = msg_r = msg
  360. else:
  361. def msg(s): sys.stderr.write(s+"\n")
  362. def vmsg(s):
  363. if opt.verbose: sys.stderr.write(s+"\n")
  364. def msg_r(s): sys.stderr.write(s)
  365. def vmsg_r(s):
  366. if opt.verbose: sys.stderr.write(s)
  367. stderr_save = sys.stderr
  368. def silence():
  369. if not (opt.verbose or opt.exact_output):
  370. sys.stderr = open("/dev/null","a")
  371. def end_silence():
  372. if not (opt.verbose or opt.exact_output):
  373. sys.stderr = stderr_save
  374. def errmsg(s): stderr_save.write(s+"\n")
  375. def errmsg_r(s): stderr_save.write(s)
  376. if opt.list_cmds:
  377. fs = " {:<{w}} - {}"
  378. Msg("AVAILABLE COMMANDS:")
  379. w = max([len(i) for i in cmd_data])
  380. for cmd in cmd_data:
  381. Msg(fs.format(cmd,cmd_data[cmd][1],w=w))
  382. w = max([len(i) for i in meta_cmds])
  383. Msg("\nAVAILABLE METACOMMANDS:")
  384. for cmd in meta_cmds:
  385. Msg(fs.format(cmd," ".join(meta_cmds[cmd]),w=w))
  386. w = max([len(i) for i in cmd_groups.keys()])
  387. Msg("\nAVAILABLE COMMAND GROUPS:")
  388. for g in cmd_groups.keys():
  389. Msg(fs.format(g," ".join(cmd_groups[g]),w=w))
  390. Msg("\nAVAILABLE UTILITIES:")
  391. w = max([len(i) for i in utils])
  392. for cmd in sorted(utils):
  393. Msg(fs.format(cmd,utils[cmd],w=w))
  394. sys.exit()
  395. import pexpect,time,re
  396. from mmgen.util import get_data_from_file,write_to_file,get_lines_from_file
  397. def my_send(p,t,delay=send_delay,s=False):
  398. if delay: time.sleep(delay)
  399. ret = p.send(t) # returns num bytes written
  400. if delay: time.sleep(delay)
  401. if opt.verbose:
  402. ls = "" if opt.debug or not s else " "
  403. es = "" if s else " "
  404. msg("%sSEND %s%s" % (ls,es,yellow("'%s'"%t.replace('\n',r'\n'))))
  405. return ret
  406. def my_expect(p,s,t='',delay=send_delay,regex=False,nonl=False):
  407. quo = "'" if type(s) == str else ""
  408. if opt.verbose: msg_r("EXPECT %s" % yellow(quo+str(s)+quo))
  409. else: msg_r("+")
  410. try:
  411. if s == '': ret = 0
  412. else:
  413. f = p.expect if regex else p.expect_exact
  414. ret = f(s,timeout=3)
  415. except pexpect.TIMEOUT:
  416. errmsg(red("\nERROR. Expect %s%s%s timed out. Exiting" % (quo,s,quo)))
  417. sys.exit(1)
  418. if opt.debug or (opt.verbose and type(s) != str): msg_r(" ==> %s " % ret)
  419. if ret == -1:
  420. errmsg("Error. Expect returned %s" % ret)
  421. sys.exit(1)
  422. else:
  423. if t == '':
  424. if not nonl: vmsg("")
  425. else:
  426. my_send(p,t,delay,s)
  427. return ret
  428. def get_file_with_ext(ext,mydir,delete=True):
  429. flist = [os.path.join(mydir,f) for f in os.listdir(mydir)
  430. if f == ext or f[-(len(ext)+1):] == "."+ext]
  431. if not flist: return False
  432. if len(flist) > 1:
  433. if delete:
  434. if not opt.quiet:
  435. msg("Multiple *.%s files in '%s' - deleting" % (ext,mydir))
  436. for f in flist: os.unlink(f)
  437. return False
  438. else:
  439. return flist[0]
  440. def get_addrfile_checksum(display=False):
  441. addrfile = get_file_with_ext("addrs",cfg['tmpdir'])
  442. silence()
  443. from mmgen.addr import AddrInfo
  444. chk = AddrInfo(addrfile).checksum
  445. if opt.verbose and display: msg("Checksum: %s" % cyan(chk))
  446. end_silence()
  447. return chk
  448. def verify_checksum_or_exit(checksum,chk):
  449. if checksum != chk:
  450. errmsg(red("Checksum error: %s" % chk))
  451. sys.exit(1)
  452. vmsg(green("Checksums match: %s") % (cyan(chk)))
  453. class MMGenExpect(object):
  454. def __init__(self,name,mmgen_cmd,cmd_args=[],extra_desc=""):
  455. if not opt.system:
  456. mmgen_cmd = os.path.join(os.curdir,mmgen_cmd)
  457. desc = (cmd_data[name][1],name)[int(bool(opt.names))]
  458. if extra_desc: desc += " " + extra_desc
  459. if opt.verbose or opt.exact_output:
  460. sys.stderr.write(
  461. green("Testing: %s\nExecuting " % desc) +
  462. cyan("'%s %s'\n" % (mmgen_cmd," ".join(cmd_args)))
  463. )
  464. else:
  465. msg_r("Testing %s: " % desc)
  466. if opt.direct_exec:
  467. os.system(" ".join([mmgen_cmd] + cmd_args))
  468. sys.exit()
  469. else:
  470. if opt.traceback:
  471. cmd_args = [mmgen_cmd] + cmd_args
  472. mmgen_cmd = tb_cmd
  473. self.p = pexpect.spawn(mmgen_cmd,cmd_args)
  474. if opt.exact_output: self.p.logfile = sys.stdout
  475. def license(self):
  476. p = "'w' for conditions and warranty info, or 'c' to continue: "
  477. my_expect(self.p,p,'c')
  478. def label(self,label="Test Label"):
  479. p = "Enter a wallet label, or hit ENTER for no label: "
  480. my_expect(self.p,p,label+"\n")
  481. def usr_rand_out(self,saved=False):
  482. m = "%suser-supplied entropy" % ("saved " if saved else "")
  483. my_expect(self.p,"Generating encryption key from OS random data plus " + m)
  484. def usr_rand(self,num_chars):
  485. rand_chars = list(getrandstr(num_chars,no_space=True))
  486. my_expect(self.p,'symbols left: ','x')
  487. try:
  488. vmsg_r("SEND ")
  489. while self.p.expect('left: ',0.1) == 0:
  490. ch = rand_chars.pop(0)
  491. msg_r(yellow(ch)+" " if opt.verbose else "+")
  492. self.p.send(ch)
  493. except:
  494. vmsg("EOT")
  495. my_expect(self.p,"ENTER to continue: ",'\n')
  496. def passphrase_new(self,desc,passphrase):
  497. my_expect(self.p,("Enter passphrase for %s: " % desc), passphrase+"\n")
  498. my_expect(self.p,"Repeat passphrase: ", passphrase+"\n")
  499. def passphrase(self,desc,passphrase,pwtype=""):
  500. if pwtype: pwtype += " "
  501. my_expect(self.p,("Enter %spassphrase for %s.*?: " % (pwtype,desc)),
  502. passphrase+"\n",regex=True)
  503. def hash_preset(self,desc,preset=''):
  504. my_expect(self.p,("Enter hash preset for %s" % desc))
  505. my_expect(self.p,("or hit ENTER .*?:"), str(preset)+"\n",regex=True)
  506. def written_to_file(self,desc,overwrite_unlikely=False,query="Overwrite? ",oo=False):
  507. s1 = "%s written to file " % desc
  508. s2 = query + "Type uppercase 'YES' to confirm: "
  509. ret = my_expect(self.p,s1 if overwrite_unlikely else [s1,s2])
  510. if ret == 1:
  511. my_send(self.p,"YES\n")
  512. if oo:
  513. outfile = self.expect_getend("Overwriting file '").rstrip("'")
  514. return outfile
  515. else:
  516. ret = my_expect(self.p,s1)
  517. outfile = self.p.readline().strip().strip("'")
  518. vmsg("%s file: %s" % (desc,cyan(outfile.replace("'",""))))
  519. return outfile
  520. def no_overwrite(self):
  521. self.expect("Overwrite? Type uppercase 'YES' to confirm: ","\n")
  522. self.expect("Exiting at user request")
  523. def tx_view(self):
  524. my_expect(self.p,r"View .*?transaction.*? \(y\)es, \(N\)o, pager \(v\)iew.*?: ","\n",regex=True)
  525. def expect_getend(self,s,regex=False):
  526. ret = self.expect(s,regex=regex,nonl=True)
  527. end = self.readline().strip()
  528. vmsg(" ==> %s" % cyan(end))
  529. return end
  530. def interactive(self):
  531. return self.p.interact()
  532. def logfile(self,arg):
  533. self.p.logfile = arg
  534. def expect(self,*args,**kwargs):
  535. return my_expect(self.p,*args,**kwargs)
  536. def send(self,*args,**kwargs):
  537. return my_send(self.p,*args,**kwargs)
  538. def readline(self):
  539. return self.p.readline()
  540. def close(self):
  541. return self.p.close()
  542. def readlines(self):
  543. return [l.rstrip()+"\n" for l in self.p.readlines()]
  544. def read(self,n=None):
  545. return self.p.read(n)
  546. from mmgen.rpc.data import TransactionInfo
  547. from decimal import Decimal
  548. from mmgen.bitcoin import verify_addr
  549. def add_fake_unspent_entry(out,address,comment):
  550. out.append(TransactionInfo(
  551. account = unicode(comment),
  552. vout = int(getrandnum(4) % 8),
  553. txid = unicode(hexlify(os.urandom(32))),
  554. amount = Decimal("%s.%s" % (10+(getrandnum(4) % 40), getrandnum(4) % 100000000)),
  555. address = address,
  556. spendable = False,
  557. scriptPubKey = ("76a914"+verify_addr(address,return_hex=True)+"88ac"),
  558. confirmations = getrandnum(4) % 500
  559. ))
  560. def create_fake_unspent_data(adata,unspent_data_file,tx_data,non_mmgen_input=''):
  561. out = []
  562. for s in tx_data.keys():
  563. sid = tx_data[s]['sid']
  564. a = adata.addrinfo(sid)
  565. for n,(idx,btcaddr) in enumerate(a.addrpairs(),1):
  566. lbl = (""," addr %02i" % n)[int(bool(n%3))]
  567. add_fake_unspent_entry(out,btcaddr,"%s:%s%s" % (sid,idx,lbl))
  568. if non_mmgen_input:
  569. from mmgen.bitcoin import privnum2addr,hextowif
  570. privnum = getrandnum(32)
  571. btcaddr = privnum2addr(privnum,compressed=True)
  572. of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
  573. write_to_file(of, hextowif("{:064x}".format(privnum),
  574. compressed=True)+"\n","compressed bitcoin key")
  575. add_fake_unspent_entry(out,btcaddr,"Non-MMGen address")
  576. # msg("\n".join([repr(o) for o in out])); sys.exit()
  577. write_to_file(unspent_data_file,repr(out),"Unspent outputs",verbose=True)
  578. def add_comments_to_addr_file(addrfile,tfile):
  579. silence()
  580. msg(green("Adding comments to address file '%s'" % addrfile))
  581. from mmgen.addr import AddrInfo
  582. a = AddrInfo(addrfile)
  583. for i in a.idxs(): a.set_comment(idx,"Test address %s" % idx)
  584. write_to_file(tfile,a.fmt_data(),{})
  585. end_silence()
  586. def make_brainwallet_file(fn):
  587. # Print random words with random whitespace in between
  588. from mmgen.mn_tirosh import words
  589. wl = words.split("\n")
  590. nwords,ws_list,max_spaces = 10," \n",5
  591. def rand_ws_seq():
  592. nchars = getrandnum(1) % max_spaces + 1
  593. return "".join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)])
  594. rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)]
  595. d = "".join(rand_pairs).rstrip() + "\n"
  596. if opt.verbose: msg_r("Brainwallet password:\n%s" % cyan(d))
  597. write_to_file(fn,d,"brainwallet password")
  598. def do_between():
  599. if opt.pause:
  600. from mmgen.util import keypress_confirm
  601. if keypress_confirm(green("Continue?"),default_yes=True):
  602. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  603. else:
  604. errmsg("Exiting at user request")
  605. sys.exit()
  606. elif opt.verbose or opt.exact_output:
  607. sys.stderr.write("\n")
  608. rebuild_list = OrderedDict()
  609. def check_needs_rerun(ts,cmd,build=False,root=True,force_delete=False,dpy=False):
  610. rerun = True if root else False # force_delete is not passed to recursive call
  611. fns = []
  612. if force_delete or not root:
  613. # does cmd produce a needed dependency(ies)?
  614. ret = ts.get_num_exts_for_cmd(cmd,dpy)
  615. if ret:
  616. for ext in ret[1]:
  617. fn = get_file_with_ext(ext,cfgs[ret[0]]['tmpdir'],delete=build)
  618. if fn:
  619. if force_delete: os.unlink(fn)
  620. else: fns.append(fn)
  621. else: rerun = True
  622. fdeps = ts.generate_file_deps(cmd)
  623. cdeps = ts.generate_cmd_deps(fdeps)
  624. for fn in fns:
  625. my_age = os.stat(fn).st_mtime
  626. for num,ext in fdeps:
  627. f = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
  628. if f and os.stat(f).st_mtime > my_age: rerun = True
  629. for cdep in cdeps:
  630. if check_needs_rerun(ts,cdep,build=build,root=False,dpy=cmd): rerun = True
  631. if build:
  632. if rerun:
  633. for fn in fns:
  634. if not root: os.unlink(fn)
  635. ts.do_cmd(cmd)
  636. if not root: do_between()
  637. else:
  638. # If prog produces multiple files:
  639. if cmd not in rebuild_list or rerun == True:
  640. rebuild_list[cmd] = (rerun,fns[0] if fns else "") # FIX
  641. return rerun
  642. def refcheck(desc,chk,refchk):
  643. vmsg("Comparing %s '%s' to stored reference" % (desc,chk))
  644. if chk == refchk:
  645. ok()
  646. else:
  647. if not opt.verbose: errmsg("")
  648. errmsg(red("""
  649. Fatal error - %s '%s' does not match reference value '%s'. Aborting test
  650. """.strip() % (desc,chk,refchk)))
  651. sys.exit(3)
  652. def check_deps(cmds):
  653. if len(cmds) != 1:
  654. msg("Usage: %s check_deps <command>" % g.prog_name)
  655. sys.exit(1)
  656. cmd = cmds[0]
  657. if cmd not in cmd_data:
  658. msg("'%s': unrecognized command" % cmd)
  659. sys.exit(1)
  660. if not opt.quiet:
  661. msg("Checking dependencies for '%s'" % (cmd))
  662. check_needs_rerun(ts,cmd,build=False)
  663. w = max(len(i) for i in rebuild_list) + 1
  664. for cmd in rebuild_list:
  665. c = rebuild_list[cmd]
  666. m = "Rebuild" if (c[0] and c[1]) else "Build" if c[0] else "OK"
  667. msg("cmd {:<{w}} {}".format(cmd+":", m, w=w))
  668. # mmsg(cmd,c)
  669. def clean(dirs=[]):
  670. ts = MMGenTestSuite()
  671. dirlist = ts.list_tmp_dirs()
  672. if not dirs: dirs = dirlist.keys()
  673. for d in sorted(dirs):
  674. if d in dirlist:
  675. cleandir(dirlist[d])
  676. else:
  677. msg("%s: invalid directory number" % d)
  678. sys.exit(1)
  679. class MMGenTestSuite(object):
  680. def __init__(self):
  681. pass
  682. def list_tmp_dirs(self):
  683. d = {}
  684. for k in cfgs: d[k] = cfgs[k]['tmpdir']
  685. return d
  686. def get_num_exts_for_cmd(self,cmd,dpy=False): # dpy ignored here
  687. num = str(cmd_data[cmd][0])
  688. dgl = cfgs[num]['dep_generators']
  689. # mmsg(num,cmd,dgl)
  690. if cmd in dgl.values():
  691. exts = [k for k in dgl if dgl[k] == cmd]
  692. return (num,exts)
  693. else:
  694. return None
  695. def do_cmd(self,cmd):
  696. d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
  697. al = [get_file_with_ext(ext,cfgs[num]['tmpdir']) for num,ext in d]
  698. global cfg
  699. cfg = cfgs[str(cmd_data[cmd][0])]
  700. self.__class__.__dict__[cmd](*([self,cmd] + al))
  701. def generate_file_deps(self,cmd):
  702. return [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
  703. def generate_cmd_deps(self,fdeps):
  704. return [cfgs[str(n)]['dep_generators'][ext] for n,ext in fdeps]
  705. def walletgen(self,name,seed_len=None):
  706. args = ["-d",cfg['tmpdir'],"-p1","-r10"]
  707. if seed_len: args += ["-l",str(seed_len)]
  708. t = MMGenExpect(name,"mmgen-walletgen", args)
  709. t.license()
  710. t.usr_rand(10)
  711. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  712. t.label()
  713. t.written_to_file("MMGen wallet")
  714. ok()
  715. def brainwalletgen_ref(self,name):
  716. sl_arg = "-l%s" % cfg['seed_len']
  717. hp_arg = "-p%s" % ref_wallet_hash_preset
  718. label = "test.py ref. wallet (pw '%s', seed len %s)" \
  719. % (ref_wallet_brainpass,cfg['seed_len'])
  720. args = ["-d",cfg['tmpdir'],hp_arg,"-r10",sl_arg,"-ib","-L",label]
  721. t = MMGenExpect(name,"mmgen-walletconv", args)
  722. t.license()
  723. t.expect("Enter brainwallet: ", ref_wallet_brainpass+"\n")
  724. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  725. t.usr_rand(10)
  726. sid = t.written_to_file("MMGen wallet").split("-")[0].split("/")[-1]
  727. refcheck("seed ID",sid,cfg['seed_id'])
  728. def refwalletgen(self,name): self.brainwalletgen_ref(name)
  729. refwalletgen1 = refwalletgen2 = refwalletgen3 = refwalletgen
  730. def passchg(self,name,walletfile):
  731. t = MMGenExpect(name,"mmgen-passchg",
  732. ["-d",cfg['tmpdir'],"-p","2","-L","New Label","-r","16",walletfile])
  733. t.license()
  734. t.passphrase("MMGen wallet",cfgs['1']['wpasswd'],pwtype="old")
  735. t.expect_getend("Hash preset changed to ")
  736. t.passphrase("MMGen wallet",cfg['wpasswd'],pwtype="new")
  737. t.expect("Repeat passphrase: ",cfg['wpasswd']+"\n")
  738. t.usr_rand(16)
  739. t.expect_getend("Label changed to ")
  740. # t.expect_getend("Key ID changed: ")
  741. t.written_to_file("MMGen wallet")
  742. ok()
  743. def walletchk_beg(self,name,args):
  744. t = MMGenExpect(name,"mmgen-walletchk", args)
  745. t.expect("Getting MMGen wallet from file '%s'" % args[-1])
  746. t.passphrase("MMGen wallet",cfg['wpasswd'])
  747. t.expect("Passphrase is OK")
  748. t.expect_getend("Valid MMGen wallet for seed ID ")
  749. return t
  750. def walletchk(self,name,walletfile):
  751. self.walletchk_beg(name,[walletfile])
  752. ok()
  753. walletchk_newpass = walletchk
  754. def addrgen(self,name,walletfile,check_ref=False):
  755. t = MMGenExpect(name,"mmgen-addrgen",["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  756. t.license()
  757. t.passphrase("MMGen wallet",cfg['wpasswd'])
  758. t.expect("Passphrase is OK")
  759. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  760. if check_ref:
  761. refcheck("address data checksum",chk,cfg['addrfile_chk'])
  762. return
  763. t.written_to_file("Addresses",oo=True)
  764. ok()
  765. def refaddrgen(self,name,walletfile):
  766. d = " (%s-bit seed)" % cfg['seed_len']
  767. self.addrgen(name,walletfile,check_ref=True)
  768. refaddrgen1 = refaddrgen2 = refaddrgen3 = refaddrgen
  769. def addrimport(self,name,addrfile):
  770. outfile = os.path.join(cfg['tmpdir'],"addrfile_w_comments")
  771. add_comments_to_addr_file(addrfile,outfile)
  772. t = MMGenExpect(name,"mmgen-addrimport",[outfile])
  773. t.expect_getend(r"Checksum for address data .*\[.*\]: ",regex=True)
  774. t.expect_getend("Validating addresses...OK. ")
  775. t.expect("Type uppercase 'YES' to confirm: ","\n")
  776. vmsg("This is a simulation, so no addresses were actually imported into the tracking\nwallet")
  777. ok()
  778. def txcreate(self,name,addrfile):
  779. self.txcreate_common(name,sources=['1'])
  780. def txcreate_common(self,name,sources=['1'],non_mmgen_input=''):
  781. if opt.verbose or opt.exact_output:
  782. sys.stderr.write(green("Generating fake transaction info\n"))
  783. silence()
  784. from mmgen.addr import AddrInfo,AddrInfoList
  785. tx_data,ail = {},AddrInfoList()
  786. from mmgen.util import parse_addr_idxs
  787. for s in sources:
  788. afile = get_file_with_ext("addrs",cfgs[s]["tmpdir"])
  789. ai = AddrInfo(afile)
  790. ail.add(ai)
  791. aix = parse_addr_idxs(cfgs[s]['addr_idx_list'])
  792. if len(aix) != addrs_per_wallet:
  793. errmsg(red("Address index list length != %s: %s" %
  794. (addrs_per_wallet,repr(aix))))
  795. sys.exit()
  796. tx_data[s] = {
  797. 'addrfile': afile,
  798. 'chk': ai.checksum,
  799. 'sid': ai.seed_id,
  800. 'addr_idxs': aix[-2:],
  801. }
  802. unspent_data_file = os.path.join(cfg['tmpdir'],"unspent.json")
  803. create_fake_unspent_data(ail,unspent_data_file,tx_data,non_mmgen_input)
  804. # make the command line
  805. from mmgen.bitcoin import privnum2addr
  806. btcaddr = privnum2addr(getrandnum(32),compressed=True)
  807. cmd_args = ["-d",cfg['tmpdir']]
  808. for num in tx_data.keys():
  809. s = tx_data[num]
  810. cmd_args += [
  811. "%s:%s,%s" % (s['sid'],s['addr_idxs'][0],cfgs[num]['amts'][0]),
  812. ]
  813. # + one BTC address
  814. # + one change address and one BTC address
  815. if num is tx_data.keys()[-1]:
  816. cmd_args += ["%s:%s" % (s['sid'],s['addr_idxs'][1])]
  817. cmd_args += ["%s,%s" % (btcaddr,cfgs[num]['amts'][1])]
  818. for num in tx_data: cmd_args += [tx_data[num]['addrfile']]
  819. os.environ["MMGEN_BOGUS_WALLET_DATA"] = unspent_data_file
  820. end_silence()
  821. if opt.verbose or opt.exact_output: sys.stderr.write("\n")
  822. t = MMGenExpect(name,"mmgen-txcreate",cmd_args)
  823. t.license()
  824. for num in tx_data.keys():
  825. t.expect_getend("Getting address data from file ")
  826. chk=t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  827. verify_checksum_or_exit(tx_data[num]['chk'],chk)
  828. # not in tracking wallet warning, (1 + num sources) times
  829. if t.expect(["Continue anyway? (y/N): ",
  830. "Unable to connect to bitcoind"]) == 0:
  831. t.send("y")
  832. else:
  833. errmsg(red("Error: unable to connect to bitcoind. Exiting"))
  834. sys.exit(1)
  835. for num in tx_data.keys():
  836. t.expect("Continue anyway? (y/N): ","y")
  837. t.expect(r"'q' = quit sorting, .*?: ","M", regex=True)
  838. t.expect(r"'q' = quit sorting, .*?: ","q", regex=True)
  839. outputs_list = [addrs_per_wallet*i + 1 for i in range(len(tx_data))]
  840. if non_mmgen_input: outputs_list.append(len(tx_data)*addrs_per_wallet + 1)
  841. t.expect("Enter a range or space-separated list of outputs to spend: ",
  842. " ".join([str(i) for i in outputs_list])+"\n")
  843. if non_mmgen_input: t.expect("Accept? (y/N): ","y")
  844. t.expect("OK? (Y/n): ","y")
  845. t.expect("Add a comment to transaction? (y/N): ","\n")
  846. t.tx_view()
  847. t.expect("Save transaction? (y/N): ","y")
  848. t.written_to_file("Transaction")
  849. ok()
  850. def txsign_end(self,t,tnum=None):
  851. t.expect("Signing transaction")
  852. t.expect("Edit transaction comment? (y/N): ","\n")
  853. t.expect("Save signed transaction? (y/N): ","y")
  854. add = " #" + tnum if tnum else ""
  855. t.written_to_file("Signed transaction" + add)
  856. def txsign(self,name,txfile,walletfile,save=True):
  857. t = MMGenExpect(name,"mmgen-txsign",
  858. ["-d",cfg['tmpdir'],txfile,walletfile])
  859. t.license()
  860. t.tx_view()
  861. t.passphrase("MMGen wallet",cfg['wpasswd'])
  862. if save:
  863. self.txsign_end(t)
  864. else:
  865. t.expect("Edit transaction comment? (y/N): ","\n")
  866. t.expect("Save signed transaction? (y/N): ","\n")
  867. t.expect("Signed transaction not saved")
  868. ok()
  869. def txsend(self,name,sigfile):
  870. t = MMGenExpect(name,"mmgen-txsend", ["-d",cfg['tmpdir'],sigfile])
  871. t.license()
  872. t.tx_view()
  873. t.expect("Edit transaction comment? (y/N): ","\n")
  874. t.expect("broadcast this transaction to the network?")
  875. t.expect("'YES, I REALLY WANT TO DO THIS' to confirm: ","\n")
  876. t.expect("Exiting at user request")
  877. vmsg("This is a simulation; no transaction was sent")
  878. ok()
  879. def walletconv_export(self,name,wf,desc,uargs=[],out_fmt="w",pw=False):
  880. opts = ["-d",cfg['tmpdir'],"-o",out_fmt] + uargs + [wf]
  881. t = MMGenExpect(name,"mmgen-walletconv",opts)
  882. t.license()
  883. t.passphrase("MMGen wallet",cfg['wpasswd'])
  884. if pw:
  885. t.passphrase_new("new "+desc,cfg['wpasswd'])
  886. t.usr_rand(10)
  887. if " ".join(desc.split()[-2:]) == "incognito data":
  888. t.expect("Generating encryption key from OS random data ")
  889. t.expect("Generating encryption key from OS random data ")
  890. ic_id = t.expect_getend("New Incog Wallet ID: ")
  891. t.expect("Generating encryption key from OS random data ")
  892. if desc == "hidden incognito data":
  893. write_to_tmpfile(cfg,incog_id_fn,ic_id)
  894. ret = t.expect(["Create? (Y/n): ","'YES' to confirm: "])
  895. if ret == 0:
  896. t.send("\n")
  897. t.expect("Enter file size: ",str(hincog_bytes)+"\n")
  898. else:
  899. t.send("YES\n")
  900. if out_fmt == "w": t.label()
  901. return t.written_to_file(capfirst(desc),oo=True)
  902. def export_seed(self,name,wf,desc="seed data",out_fmt="seed"):
  903. f = self.walletconv_export(name,wf,desc=desc,out_fmt=out_fmt)
  904. silence()
  905. msg("%s: %s" % (capfirst(desc),cyan(get_data_from_file(f,desc))))
  906. end_silence()
  907. ok()
  908. def export_mnemonic(self,name,wf):
  909. self.export_seed(name,wf,desc="mnemonic data",out_fmt="words")
  910. def export_incog(self,name,wf,desc="incognito data",out_fmt="i",add_args=[]):
  911. uargs = ["-p1","-r10"] + add_args
  912. self.walletconv_export(name,wf,desc=desc,out_fmt=out_fmt,uargs=uargs,pw=True)
  913. ok()
  914. def export_incog_hex(self,name,wf):
  915. self.export_incog(name,wf,desc="hex incognito data",out_fmt="xi")
  916. # TODO: make outdir and hidden incog compatible (ignore --outdir and warn user?)
  917. def export_incog_hidden(self,name,wf):
  918. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  919. add_args = ["-J","%s,%s"%(rf,hincog_offset)]
  920. self.export_incog(
  921. name,wf,desc="hidden incognito data",out_fmt="hi",add_args=add_args)
  922. def addrgen_seed(self,name,walletfile,foo,desc="seed data",in_fmt="seed"):
  923. stdout = (False,True)[int(desc=="seed data")] #capture output to screen once
  924. add_arg = ([],["-S"])[int(stdout)]
  925. t = MMGenExpect(name,"mmgen-addrgen", add_arg +
  926. ["-i"+in_fmt,"-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  927. t.license()
  928. t.expect_getend("Valid %s for seed ID " % desc)
  929. vmsg("Comparing generated checksum with checksum from previous address file")
  930. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  931. if stdout: t.read()
  932. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  933. # t.no_overwrite()
  934. ok()
  935. def addrgen_mnemonic(self,name,wf,foo):
  936. self.addrgen_seed(name,wf,foo,desc="mnemonic data",in_fmt="words")
  937. def addrgen_incog(self,name,wf=[],foo="",in_fmt="i",
  938. desc="incognito data",args=[]):
  939. t = MMGenExpect(name,"mmgen-addrgen",
  940. args+["-i"+in_fmt,"-d",cfg['tmpdir']]+
  941. ([wf] if wf else [])+
  942. [cfg['addr_idx_list']])
  943. t.license()
  944. t.expect_getend("Incog Wallet ID: ")
  945. t.hash_preset(desc,'1')
  946. t.passphrase("%s \w{8}" % desc, cfg['wpasswd'])
  947. vmsg("Comparing generated checksum with checksum from address file")
  948. chk = t.expect_getend(r"Checksum for address data .*?: ",regex=True)
  949. t.close()
  950. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  951. # t.no_overwrite()
  952. ok()
  953. def addrgen_incog_hex(self,name,wf,foo):
  954. self.addrgen_incog(name,wf,"",in_fmt="xi",desc="hex incognito data")
  955. def addrgen_incog_hidden(self,name,wf,foo):
  956. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  957. self.addrgen_incog(name,[],"",in_fmt="hi",desc="hidden incognito data",
  958. args=["-H","%s,%s"%(rf,hincog_offset),"-l",str(hincog_seedlen)])
  959. def keyaddrgen(self,name,walletfile,check_ref=False):
  960. t = MMGenExpect(name,"mmgen-keygen",
  961. ["-d",cfg['tmpdir'],walletfile,cfg['addr_idx_list']])
  962. t.license()
  963. t.passphrase("MMGen wallet",cfg['wpasswd'])
  964. chk = t.expect_getend(r"Checksum for key-address data .*?: ",regex=True)
  965. if check_ref:
  966. refcheck("key-address data checksum",chk,cfg['keyaddrfile_chk'])
  967. return
  968. t.expect("Encrypt key list? (y/N): ","y")
  969. t.hash_preset("new key list",'1')
  970. t.passphrase_new("new key list",cfg['kapasswd'])
  971. t.written_to_file("Secret keys",oo=True)
  972. ok()
  973. def refkeyaddrgen(self,name,walletfile):
  974. self.keyaddrgen(name,walletfile,check_ref=True)
  975. refkeyaddrgen1 = refkeyaddrgen2 = refkeyaddrgen3 = refkeyaddrgen
  976. def txsign_keyaddr(self,name,keyaddr_file,txfile):
  977. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],"-M",keyaddr_file,txfile])
  978. t.license()
  979. t.hash_preset("key-address file",'1')
  980. t.passphrase("key-address file",cfg['kapasswd'])
  981. t.expect("Check key-to-address validity? (y/N): ","y")
  982. t.tx_view()
  983. self.txsign_end(t)
  984. ok()
  985. def walletgen2(self,name):
  986. self.walletgen(name,seed_len=128)
  987. def addrgen2(self,name,walletfile):
  988. self.addrgen(name,walletfile)
  989. def txcreate2(self,name,addrfile):
  990. self.txcreate_common(name,sources=['2'])
  991. def txsign2(self,name,txf1,wf1,txf2,wf2):
  992. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],txf1,wf1,txf2,wf2])
  993. t.license()
  994. for cnum in ('1','2'):
  995. t.tx_view()
  996. t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd'])
  997. self.txsign_end(t,cnum)
  998. ok()
  999. def export_mnemonic2(self,name,walletfile):
  1000. self.export_mnemonic(name,walletfile)
  1001. def walletgen3(self,name):
  1002. self.walletgen(name)
  1003. def addrgen3(self,name,walletfile):
  1004. self.addrgen(name,walletfile)
  1005. def txcreate3(self,name,addrfile1,addrfile2):
  1006. self.txcreate_common(name,sources=['1','3'])
  1007. def txsign3(self,name,wf1,wf2,txf2):
  1008. t = MMGenExpect(name,"mmgen-txsign", ["-d",cfg['tmpdir'],wf1,wf2,txf2])
  1009. t.license()
  1010. t.tx_view()
  1011. for cnum in ('1','3'):
  1012. # t.expect_getend("Getting MMGen wallet data from file ")
  1013. t.passphrase("MMGen wallet",cfgs[cnum]['wpasswd'])
  1014. self.txsign_end(t)
  1015. ok()
  1016. def brainwalletgen_pwfile(self,name):
  1017. bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename'])
  1018. make_brainwallet_file(bwf)
  1019. seed_len = str(cfg['seed_len'])
  1020. args = ["-d",cfg['tmpdir'],"-p1","-r10","-l"+seed_len,"-ib"]
  1021. t = MMGenExpect(name,"mmgen-walletconv", args + [bwf])
  1022. t.license()
  1023. t.passphrase_new("new MMGen wallet",cfg['wpasswd'])
  1024. t.usr_rand(10)
  1025. t.label()
  1026. t.written_to_file("MMGen wallet")
  1027. ok()
  1028. def walletgen4(self,name): self.brainwalletgen_pwfile(name)
  1029. def addrgen4(self,name,walletfile):
  1030. self.addrgen(name,walletfile)
  1031. def txcreate4(self,name,f1,f2,f3,f4):
  1032. self.txcreate_common(name,sources=['1','2','3','4'],non_mmgen_input='4')
  1033. def txsign4(self,name,f1,f2,f3,f4,f5):
  1034. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  1035. t = MMGenExpect(name,"mmgen-txsign",
  1036. ["-d",cfg['tmpdir'],"-i","brain","-b"+cfg['bw_params'],"-p1","-k",non_mm_fn,f1,f2,f3,f4,f5])
  1037. t.license()
  1038. t.tx_view()
  1039. for cnum,desc in ('1',"incognito data"),('3',"MMGen wallet"):
  1040. t.passphrase(("%s" % desc),cfgs[cnum]['wpasswd'])
  1041. self.txsign_end(t)
  1042. ok()
  1043. def tool_encrypt(self,name,infile=""):
  1044. if infile:
  1045. infn = infile
  1046. else:
  1047. d = os.urandom(1033)
  1048. tmp_fn = cfg['tool_enc_infn']
  1049. write_to_tmpfile(cfg,tmp_fn,d)
  1050. infn = get_tmpfile_fn(cfg,tmp_fn)
  1051. t = MMGenExpect(name,"mmgen-tool",["-d",cfg['tmpdir'],"encrypt",infn])
  1052. t.hash_preset("user data",'1')
  1053. t.passphrase_new("user data",tool_enc_passwd)
  1054. t.written_to_file("Encrypted data")
  1055. ok()
  1056. # Generate the reference mmenc file
  1057. # def tool_encrypt_ref(self,name):
  1058. # infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn'])
  1059. # write_to_file(infn,cfg['tool_enc_reftext'],silent=True)
  1060. # self.tool_encrypt(name,infn)
  1061. def tool_decrypt(self,name,f1,f2):
  1062. of = name + ".out"
  1063. t = MMGenExpect(name,"mmgen-tool",
  1064. ["-d",cfg['tmpdir'],"decrypt",f2,"outfile="+of,"hash_preset=1"])
  1065. t.passphrase("user data",tool_enc_passwd)
  1066. t.written_to_file("Decrypted data")
  1067. d1 = read_from_file(f1)
  1068. d2 = read_from_file(get_tmpfile_fn(cfg,of))
  1069. cmp_or_die(d1,d2)
  1070. def tool_find_incog_data(self,name,f1,f2):
  1071. i_id = read_from_file(f2).rstrip()
  1072. vmsg("Incog ID: %s" % cyan(i_id))
  1073. t = MMGenExpect(name,"mmgen-tool",
  1074. ["-d",cfg['tmpdir'],"find_incog_data",f1,i_id])
  1075. o = t.expect_getend("Incog data for ID %s found at offset " % i_id)
  1076. os.unlink(f1)
  1077. cmp_or_die(hincog_offset,int(o))
  1078. def walletconv_out(self,name,desc,out_fmt="w",uopts=[],uopts_chk=[],pw=False):
  1079. opts = ["-d",cfg['tmpdir'],"-r10","-p1","-o",out_fmt] + uopts
  1080. infile = os.path.join(ref_dir,cfg['seed_id']+".mmwords")
  1081. t = MMGenExpect(name,"mmgen-walletconv",opts+[infile],extra_desc="(convert)")
  1082. t.license()
  1083. if pw:
  1084. t.passphrase_new("new "+desc,cfg['wpasswd'])
  1085. t.usr_rand(10)
  1086. if " ".join(desc.split()[-2:]) == "incognito data":
  1087. for i in (1,2,3):
  1088. t.expect("Generating encryption key from OS random data ")
  1089. if desc == "hidden incognito data":
  1090. ret = t.expect(["Create? (Y/n): ","'YES' to confirm: "])
  1091. if ret == 0:
  1092. t.send("\n")
  1093. t.expect("Enter file size: ",str(hincog_bytes)+"\n")
  1094. else:
  1095. t.send("YES\n")
  1096. if out_fmt == "w": t.label()
  1097. wf = t.written_to_file(capfirst(desc),oo=True)
  1098. ok()
  1099. if desc == "hidden incognito data":
  1100. self.keygen_chksum_chk_hincog(name,cfg['seed_id'],uopts_chk)
  1101. else:
  1102. self.keygen_chksum_chk(name,wf,cfg['seed_id'],pw=pw)
  1103. def walletconv_in(self,name,infile,desc,uopts=[],pw=False,oo=False):
  1104. opts = ["-d",cfg['tmpdir'],"-o","words","-r10"]
  1105. if_arg = [infile] if infile else []
  1106. d = "(convert)"
  1107. t = MMGenExpect(name,"mmgen-walletconv",opts+uopts+if_arg,extra_desc=d)
  1108. t.license()
  1109. if desc == "brainwallet":
  1110. t.expect("Enter brainwallet: ",ref_wallet_brainpass+"\n")
  1111. if pw:
  1112. t.passphrase(desc,cfg['wpasswd'])
  1113. if name[:19] == "ref_hincog_conv_old":
  1114. t.expect("Is the seed ID correct? (Y/n): ","\n")
  1115. else:
  1116. t.expect(["Passphrase is OK"," are correct"])
  1117. # Output
  1118. wf = t.written_to_file("Mnemonic data",oo=oo)
  1119. t.close()
  1120. ok()
  1121. # back check of result
  1122. d = "(check)"
  1123. self.keygen_chksum_chk(name,wf,cfg['seed_id'])
  1124. # Saved reference file tests
  1125. def ref_wallet_conv(self,name):
  1126. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1127. self.walletconv_in(name,wf,"MMGen wallet",pw=True,oo=True)
  1128. def ref_mn_conv(self,name,ext="mmwords",desc="Mnemonic data"):
  1129. wf = os.path.join(ref_dir,cfg['seed_id']+"."+ext)
  1130. self.walletconv_in(name,wf,desc,oo=True)
  1131. def ref_seed_conv(self,name):
  1132. self.ref_mn_conv(name,ext="mmseed",desc="Seed data")
  1133. def ref_brain_conv(self,name):
  1134. uopts = ["-i","b","-p","1","-l",str(cfg['seed_len'])]
  1135. self.walletconv_in(name,None,"brainwallet",uopts,oo=True)
  1136. def ref_incog_conv(self,name,wfk="ic_wallet",in_fmt="i",desc="incognito data"):
  1137. uopts = ["-i",in_fmt,"-p","1","-l",str(cfg['seed_len'])]
  1138. wf = os.path.join(ref_dir,cfg[wfk])
  1139. self.walletconv_in(name,wf,desc,uopts,oo=True,pw=True)
  1140. def ref_incox_conv(self,name):
  1141. self.ref_incog_conv(name,in_fmt="xi",wfk="ic_wallet_hex",desc="hex incognito data")
  1142. def ref_hincog_conv(self,name,wfk='hic_wallet',add_uopts=[]):
  1143. ic_f = os.path.join(ref_dir,cfg[wfk])
  1144. uopts = ["-i","hi","-p","1","-l",str(cfg['seed_len'])] + add_uopts
  1145. hi_opt = ["-H","%s,%s" % (ic_f,ref_wallet_incog_offset)]
  1146. self.walletconv_in(name,None,"hidden incognito data",uopts+hi_opt,oo=True,pw=True)
  1147. def ref_hincog_conv_old(self,name):
  1148. self.ref_hincog_conv(name,wfk='hic_wallet_old',add_uopts=["-O"])
  1149. def ref_wallet_conv_out(self,name):
  1150. self.walletconv_out(name,"MMGen wallet","w",pw=True)
  1151. def ref_mn_conv_out(self,name):
  1152. self.walletconv_out(name,"mnemonic data","mn")
  1153. def ref_seed_conv_out(self,name):
  1154. self.walletconv_out(name,"seed data","seed")
  1155. def ref_incog_conv_out(self,name):
  1156. self.walletconv_out(name,"incognito data",out_fmt="i",pw=True)
  1157. def ref_incox_conv_out(self,name):
  1158. self.walletconv_out(name,"hex incognito data",out_fmt="xi",pw=True)
  1159. def ref_hincog_conv_out(self,name,extra_uopts=[]):
  1160. ic_f = os.path.join(cfg['tmpdir'],"rand.data")
  1161. hi_parms = "%s,%s" % (ic_f,ref_wallet_incog_offset)
  1162. sl_parm = "-l" + str(cfg['seed_len'])
  1163. self.walletconv_out(name,
  1164. "hidden incognito data", "hi",
  1165. uopts=["-J",hi_parms,sl_parm] + extra_uopts,
  1166. uopts_chk=["-H",hi_parms,sl_parm],
  1167. pw=True
  1168. )
  1169. ref_wallet_conv1 = ref_wallet_conv2 = ref_wallet_conv3 = ref_wallet_conv
  1170. ref_mn_conv1 = ref_mn_conv2 = ref_mn_conv3 = ref_mn_conv
  1171. ref_seed_conv1 = ref_seed_conv2 = ref_seed_conv3 = ref_seed_conv
  1172. ref_brain_conv1 = ref_brain_conv2 = ref_brain_conv3 = ref_brain_conv
  1173. ref_incog_conv1 = ref_incog_conv2 = ref_incog_conv3 = ref_incog_conv
  1174. ref_incox_conv1 = ref_incox_conv2 = ref_incox_conv3 = ref_incox_conv
  1175. ref_hincog_conv1 = ref_hincog_conv2 = ref_hincog_conv3 = ref_hincog_conv
  1176. ref_hincog_conv_old1 = ref_hincog_conv_old2 = ref_hincog_conv_old3 = ref_hincog_conv_old
  1177. ref_wallet_conv_out1 = ref_wallet_conv_out2 = ref_wallet_conv_out3 = ref_wallet_conv_out
  1178. ref_mn_conv_out1 = ref_mn_conv_out2 = ref_mn_conv_out3 = ref_mn_conv_out
  1179. ref_seed_conv_out1 = ref_seed_conv_out2 = ref_seed_conv_out3 = ref_seed_conv_out
  1180. ref_incog_conv_out1 = ref_incog_conv_out2 = ref_incog_conv_out3 = ref_incog_conv_out
  1181. ref_incox_conv_out1 = ref_incox_conv_out2 = ref_incox_conv_out3 = ref_incox_conv_out
  1182. ref_hincog_conv_out1 = ref_hincog_conv_out2 = ref_hincog_conv_out3 = ref_hincog_conv_out
  1183. def ref_wallet_chk(self,name):
  1184. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1185. self.walletchk(name,wf)
  1186. ref_wallet_chk1 = ref_wallet_chk2 = ref_wallet_chk3 = ref_wallet_chk
  1187. def ref_seed_chk(self,name,ext=g.seed_ext):
  1188. wf = os.path.join(ref_dir,"%s.%s" % (cfg['seed_id'],ext))
  1189. desc = "seed data" if ext == g.seed_ext else "mnemonic"
  1190. self.keygen_chksum_chk(name,wf,cfg['seed_id'])
  1191. ref_seed_chk1 = ref_seed_chk2 = ref_seed_chk3 = ref_seed_chk
  1192. def ref_mn_chk(self,name): self.ref_seed_chk(name,ext=g.mn_ext)
  1193. ref_mn_chk1 = ref_mn_chk2 = ref_mn_chk3 = ref_mn_chk
  1194. def ref_brain_chk(self,name,bw_file=ref_bw_file):
  1195. wf = os.path.join(ref_dir,bw_file)
  1196. args = ["-l%s" % cfg['seed_len'], "-p"+ref_bw_hash_preset]
  1197. self.keygen_chksum_chk(name,wf,cfg['ref_bw_seed_id'],args)
  1198. def keygen_chksum_chk_hincog(self,name,seed_id,hincog_parm):
  1199. t = MMGenExpect(name,"mmgen-keygen", ["-p1","-q","-S","-A"]+hincog_parm+["1"],extra_desc="(check)")
  1200. t.passphrase("",cfg['wpasswd'])
  1201. t.expect("Encrypt key list? (y/N): ","\n")
  1202. t.expect("ignored by MMGen.\r\n")
  1203. chk = t.readline()[:8]
  1204. vmsg("Seed ID: %s" % cyan(chk))
  1205. cmp_or_die(seed_id,chk)
  1206. def keygen_chksum_chk(self,name,wf,seed_id,args=[],pw=False):
  1207. hp_arg = ["-p1"] if pw else []
  1208. t = MMGenExpect(name,"mmgen-keygen",
  1209. ["-l",str(cfg['seed_len']),"-q","-S","-A"]+args+hp_arg+[wf,"1"],
  1210. extra_desc="(check)")
  1211. if pw:
  1212. t.passphrase("",cfg['wpasswd'])
  1213. t.expect("Encrypt key list? (y/N): ","\n")
  1214. t.expect("ignored by MMGen.\r\n")
  1215. chk = t.readline()[:8]
  1216. vmsg("Seed ID: %s" % cyan(chk))
  1217. cmp_or_die(seed_id,chk)
  1218. # Use this for encrypted wallets instead of keygen_chksum_chk()
  1219. def walletchk_chksum_chk(self,name,wf,seed_id,uopts=[]):
  1220. t = MMGenExpect(name,"mmgen-walletchk",["-v", wf]+uopts,
  1221. extra_desc="(check)")
  1222. t.passphrase("",cfg['wpasswd'])
  1223. chk = t.expect_getend("Seed ID checksum OK (")[:8]
  1224. t.close()
  1225. cmp_or_die(seed_id,chk)
  1226. ref_brain_chk1 = ref_brain_chk2 = ref_brain_chk3 = ref_brain_chk
  1227. def ref_brain_chk_spc3(self,name):
  1228. self.ref_brain_chk(name,bw_file=ref_bw_file_spc)
  1229. def ref_hincog_chk(self,name,desc="hidden incognito data"):
  1230. for wtype,edesc,earg in ('hic_wallet','',[]), \
  1231. ('hic_wallet_old','(old format)',["-O"]):
  1232. ic_arg = "%s,%s" % (
  1233. os.path.join(ref_dir,cfg[wtype]),
  1234. ref_wallet_incog_offset
  1235. )
  1236. t = MMGenExpect(name,"mmgen-keygen",["-l",str(cfg['seed_len']),
  1237. "-q","-A"]+earg+["-H"]+[ic_arg]+['1'],extra_desc=edesc)
  1238. t.hash_preset(desc,"1")
  1239. t.passphrase(desc,cfg['wpasswd'])
  1240. if wtype == 'hic_wallet_old':
  1241. t.expect("Is the seed ID correct? (Y/n): ","\n")
  1242. chk = t.expect_getend("Seed ID: ")
  1243. t.expect("Encrypt key list? (y/N): ","\n")
  1244. t.close()
  1245. cmp_or_die(cfg['seed_id'],chk)
  1246. ref_hincog_chk1 = ref_hincog_chk2 = ref_hincog_chk3 = ref_hincog_chk
  1247. def ref_addrfile_chk(self,name,ftype="addr"):
  1248. wf = os.path.join(ref_dir,cfg['ref_'+ftype+'file'])
  1249. t = MMGenExpect(name,"mmgen-tool",[ftype+"file_chksum",wf])
  1250. if ftype == "keyaddr":
  1251. w = "key-address file"
  1252. t.hash_preset(w,ref_kafile_hash_preset)
  1253. t.passphrase(w,ref_kafile_pass)
  1254. t.expect("Check key-to-address validity? (y/N): ","y")
  1255. o = t.expect_getend("Checksum for .*address data .*: ",regex=True)
  1256. cmp_or_die(cfg['ref_'+ftype+'file_chksum'],o)
  1257. def ref_keyaddrfile_chk(self,name):
  1258. self.ref_addrfile_chk(name,ftype="keyaddr")
  1259. # def txcreate8(self,name,addrfile):
  1260. # self.txcreate_common(name,sources=['8'])
  1261. def ref_tx_chk(self,name):
  1262. tf = os.path.join(ref_dir,cfg['ref_tx_file'])
  1263. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1264. self.txsign(name,tf,wf,save=False)
  1265. def ref_tool_decrypt(self,name):
  1266. f = os.path.join(ref_dir,ref_enc_fn)
  1267. t = MMGenExpect(name,"mmgen-tool",
  1268. ["-q","decrypt",f,"outfile=-","hash_preset=1"])
  1269. t.passphrase("user data",tool_enc_passwd)
  1270. t.readline()
  1271. import re
  1272. o = re.sub('\r\n','\n',t.read())
  1273. cmp_or_die(sample_text,o)
  1274. # main()
  1275. if opt.pause:
  1276. import termios,atexit
  1277. fd = sys.stdin.fileno()
  1278. old = termios.tcgetattr(fd)
  1279. def at_exit():
  1280. termios.tcsetattr(fd, termios.TCSADRAIN, old)
  1281. atexit.register(at_exit)
  1282. start_time = int(time.time())
  1283. ts = MMGenTestSuite()
  1284. for cfg in sorted(cfgs): mk_tmpdir(cfgs[cfg])
  1285. try:
  1286. if cmd_args:
  1287. for arg in cmd_args:
  1288. if arg in utils:
  1289. globals()[arg](cmd_args[cmd_args.index(arg)+1:])
  1290. sys.exit()
  1291. elif arg in meta_cmds:
  1292. for cmd in meta_cmds[arg]:
  1293. check_needs_rerun(ts,cmd,build=True)
  1294. elif arg in cmd_groups.keys():
  1295. for cmd in cmd_groups[arg]:
  1296. check_needs_rerun(ts,cmd,build=True)
  1297. elif arg in cmd_data:
  1298. check_needs_rerun(ts,arg,build=True)
  1299. else:
  1300. die(1,"%s: unrecognized command" % arg)
  1301. else:
  1302. clean()
  1303. for cmd in cmd_data:
  1304. ts.do_cmd(cmd)
  1305. if cmd is not cmd_data.keys()[-1]: do_between()
  1306. except:
  1307. sys.stderr = stderr_save
  1308. raise
  1309. t = int(time.time()) - start_time
  1310. sys.stderr.write(green(
  1311. "All requested tests finished OK, elapsed time: %02i:%02i\n"
  1312. % (t/60,t%60)))