test.py 55 KB

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