test.py 55 KB

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