test.py 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737
  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2017 Philemon <mmgen-py@yandex.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. test/test.py: Test suite for the MMGen suite
  20. """
  21. import sys,os,subprocess,shutil,time,re
  22. repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir)))
  23. os.chdir(repo_root)
  24. sys.path.__setitem__(0,repo_root)
  25. # Import these _after_ local path's been added to sys.path
  26. from mmgen.common import *
  27. from mmgen.test import *
  28. from mmgen.protocol import CoinProtocol
  29. g.quiet = False # if 'quiet' was set in config file, disable here
  30. os.environ['MMGEN_QUIET'] = '0' # and for the spawned scripts
  31. log_file = 'test.py_log'
  32. hincog_fn = 'rand_data'
  33. hincog_bytes = 1024*1024
  34. hincog_offset = 98765
  35. hincog_seedlen = 256
  36. incog_id_fn = 'incog_id'
  37. non_mmgen_fn = 'coinkey'
  38. pwfile = 'passwd_file'
  39. ref_dir = os.path.join('test','ref')
  40. ref_wallet_brainpass = 'abc'
  41. ref_wallet_hash_preset = '1'
  42. ref_wallet_incog_offset = 123
  43. from mmgen.obj import MMGenTXLabel,PrivKey
  44. from mmgen.addr import AddrGenerator,KeyGenerator,AddrList,AddrData,AddrIdxList
  45. ref_tx_label = ''.join([unichr(i) for i in range(65,91) +
  46. range(1040,1072) + # cyrillic
  47. range(913,939) + # greek
  48. range(97,123)])[:MMGenTXLabel.max_len]
  49. ref_bw_hash_preset = '1'
  50. ref_bw_file = 'wallet.mmbrain'
  51. ref_bw_file_spc = 'wallet-spaced.mmbrain'
  52. ref_kafile_pass = 'kafile password'
  53. ref_kafile_hash_preset = '1'
  54. ref_enc_fn = 'sample-text.mmenc'
  55. tool_enc_passwd = "Scrypt it, don't hash it!"
  56. sample_text = \
  57. 'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks\n'
  58. # Laggy flash media cause pexpect to crash, so create a temporary directory
  59. # under '/dev/shm' and put datadir and temp files here.
  60. shortopts = ''.join([e[1:] for e in sys.argv if len(e) > 1 and e[0] == '-' and e[1] != '-'])
  61. shortopts = ['-'+e for e in list(shortopts)]
  62. data_dir = os.path.join('test','data_dir')
  63. if not any(e in ('--skip-deps','--resume','-S','-r') for e in sys.argv+shortopts):
  64. if g.platform == 'win':
  65. try: os.listdir(data_dir)
  66. except: pass
  67. else:
  68. try: shutil.rmtree(data_dir)
  69. except: # we couldn't remove data dir - perhaps regtest daemon is running
  70. try: subprocess.call(['python',os.path.join('cmds','mmgen-regtest'),'stop'])
  71. except: rdie(1,'Unable to remove data dir!')
  72. else:
  73. time.sleep(2)
  74. shutil.rmtree(data_dir)
  75. os.mkdir(data_dir,0755)
  76. else:
  77. d,pfx = '/dev/shm','mmgen-test-'
  78. try:
  79. subprocess.call('rm -rf %s/%s*'%(d,pfx),shell=True)
  80. except Exception as e:
  81. die(2,'Unable to delete directory tree %s/%s* (%s)'%(d,pfx,e))
  82. try:
  83. import tempfile
  84. shm_dir = tempfile.mkdtemp('',pfx,d)
  85. except Exception as e:
  86. die(2,'Unable to create temporary directory in %s (%s)'%(d,e))
  87. dd = os.path.join(shm_dir,'data_dir')
  88. os.mkdir(dd,0755)
  89. try: os.unlink(data_dir)
  90. except: pass
  91. os.symlink(dd,data_dir)
  92. opts_data = lambda: {
  93. 'desc': 'Test suite for the MMGen suite',
  94. 'usage':'[options] [command(s) or metacommand(s)]',
  95. 'options': """
  96. -h, --help Print this help message
  97. --, --longhelp Print help message for long options (common options)
  98. -b, --buf-keypress Use buffered keypresses as with real human input
  99. -c, --print-cmdline Print the command line of each spawned command
  100. -d, --debug-scripts Turn on debugging output in executed scripts
  101. -x, --debug-pexpect Produce debugging output for pexpect calls
  102. -D, --direct-exec Bypass pexpect and execute a command directly (for
  103. debugging only)
  104. -e, --exact-output Show the exact output of the MMGen script(s) being run
  105. -g, --segwit Generate and use Segwit addresses
  106. -G, --segwit-random Generate and use a random mix of Segwit and Legacy addrs
  107. -l, --list-cmds List and describe the commands in the test suite
  108. -L, --log Log commands to file {lf}
  109. -n, --names Display command names instead of descriptions
  110. -O, --popen-spawn Use pexpect's popen_spawn instead of popen (always true, so ignored)
  111. -p, --pause Pause between tests, resuming on keypress
  112. -P, --profile Record the execution time of each script
  113. -q, --quiet Produce minimal output. Suppress dependency info
  114. -r, --resume=c Resume at command 'c' after interrupted run
  115. -s, --system Test scripts and modules installed on system rather
  116. than those in the repo root
  117. -S, --skip-deps Skip dependency checking for command
  118. -u, --usr-random Get random data interactively from user
  119. -t, --traceback Run the command inside the '{tbc}' script
  120. -v, --verbose Produce more verbose output
  121. -W, --no-dw-delete Don't remove default wallet from data dir after dw tests are done
  122. """.format(tbc=g.traceback_cmd,lf=log_file),
  123. 'notes': """
  124. If no command is given, the whole suite of tests is run.
  125. """
  126. }
  127. sys.argv = [sys.argv[0]] + ['--data-dir',data_dir] + sys.argv[1:]
  128. cmd_args = opts.init(opts_data)
  129. opt.popen_spawn = True # popen has issues, so use popen_spawn always
  130. ref_subdir = '' if g.proto.base_coin == 'BTC' else g.proto.name
  131. altcoin_pfx = '' if g.proto.base_coin == 'BTC' else '-'+g.proto.base_coin
  132. tn_ext = ('','.testnet')[g.testnet]
  133. coin_sel = g.coin.lower()
  134. if g.coin == 'B2X': coin_sel = 'btc'
  135. fork = {'bch':'btc','btc':'btc','ltc':'ltc'}[coin_sel]
  136. tx_fee = {'btc':'0.0001','bch':'0.001','ltc':'0.01'}[coin_sel]
  137. txbump_fee = {'btc':'123s','bch':'567s','ltc':'12345s'}[coin_sel]
  138. rtFundAmt = {'btc':'500','bch':'500','ltc':'5500'}[coin_sel]
  139. rtFee = {
  140. 'btc': ('20s','10s','60s','0.0001','10s','20s'),
  141. 'bch': ('20s','10s','60s','0.0001','10s','20s'),
  142. 'ltc': ('1000s','500s','1500s','0.05','400s','1000s')
  143. }[coin_sel]
  144. rtBals = {
  145. 'btc': ('499.999942','399.9998214','399.9998079','399.9996799','13.00000000','986.99957990','999.99957990'),
  146. 'bch': ('499.9999416','399.9999124','399.99989','399.9997616','276.22339397','723.77626763','999.99966160'),
  147. 'ltc': ('5499.9971','5399.994085','5399.993545','5399.987145','13.00000000','10986.93714500','10999.93714500'),
  148. }[coin_sel]
  149. rtBobOp3 = {'btc':'S:2','bch':'L:3','ltc':'S:2'}[coin_sel]
  150. if opt.segwit and 'S' not in g.proto.mmtypes:
  151. die(1,'--segwit option incompatible with {}'.format(g.proto.__name__))
  152. def randbool():
  153. return hexlify(os.urandom(1))[1] in '12345678'
  154. def get_segwit_val():
  155. return randbool() if opt.segwit_random else True if opt.segwit else False
  156. cfgs = {
  157. '15': {
  158. 'tmpdir': os.path.join('test','tmp15'),
  159. 'wpasswd': 'Dorian',
  160. 'kapasswd': 'Grok the blockchain',
  161. 'addr_idx_list': '12,99,5-10,5,12', # 8 addresses
  162. 'dep_generators': {
  163. pwfile: 'walletgen_dfl_wallet',
  164. 'addrs': 'addrgen_dfl_wallet',
  165. 'rawtx': 'txcreate_dfl_wallet',
  166. 'sigtx': 'txsign_dfl_wallet',
  167. 'mmseed': 'export_seed_dfl_wallet',
  168. 'del_dw_run': 'delete_dfl_wallet',
  169. },
  170. 'segwit': get_segwit_val()
  171. },
  172. '16': {
  173. 'tmpdir': os.path.join('test','tmp16'),
  174. 'wpasswd': 'My changed password',
  175. 'hash_preset': '2',
  176. 'dep_generators': {
  177. pwfile: 'passchg_dfl_wallet',
  178. },
  179. 'segwit': get_segwit_val()
  180. },
  181. '17': { 'tmpdir': os.path.join('test','tmp17') },
  182. '18': { 'tmpdir': os.path.join('test','tmp18') },
  183. '19': { 'tmpdir': os.path.join('test','tmp19'), 'wpasswd':'abc' },
  184. '1': {
  185. 'tmpdir': os.path.join('test','tmp1'),
  186. 'wpasswd': 'Dorian',
  187. 'kapasswd': 'Grok the blockchain',
  188. 'addr_idx_list': '12,99,5-10,5,12', # 8 addresses
  189. 'dep_generators': {
  190. pwfile: 'walletgen',
  191. 'mmdat': 'walletgen',
  192. 'addrs': 'addrgen',
  193. 'rawtx': 'txcreate',
  194. 'txbump': 'txbump',
  195. 'sigtx': 'txsign',
  196. 'mmwords': 'export_mnemonic',
  197. 'mmseed': 'export_seed',
  198. 'mmhex': 'export_hex',
  199. 'mmincog': 'export_incog',
  200. 'mmincox': 'export_incog_hex',
  201. hincog_fn: 'export_incog_hidden',
  202. incog_id_fn: 'export_incog_hidden',
  203. 'akeys.mmenc': 'keyaddrgen'
  204. },
  205. 'segwit': get_segwit_val()
  206. },
  207. '2': {
  208. 'tmpdir': os.path.join('test','tmp2'),
  209. 'wpasswd': 'Hodling away',
  210. 'addr_idx_list': '37,45,3-6,22-23', # 8 addresses
  211. 'seed_len': 128,
  212. 'dep_generators': {
  213. 'mmdat': 'walletgen2',
  214. 'addrs': 'addrgen2',
  215. 'rawtx': 'txcreate2',
  216. 'sigtx': 'txsign2',
  217. 'mmwords': 'export_mnemonic2',
  218. },
  219. 'segwit': get_segwit_val()
  220. },
  221. '3': {
  222. 'tmpdir': os.path.join('test','tmp3'),
  223. 'wpasswd': 'Major miner',
  224. 'addr_idx_list': '73,54,1022-1023,2-5', # 8 addresses
  225. 'dep_generators': {
  226. 'mmdat': 'walletgen3',
  227. 'addrs': 'addrgen3',
  228. 'rawtx': 'txcreate3',
  229. 'sigtx': 'txsign3'
  230. },
  231. 'segwit': get_segwit_val()
  232. },
  233. '4': {
  234. 'tmpdir': os.path.join('test','tmp4'),
  235. 'wpasswd': 'Hashrate good',
  236. 'addr_idx_list': '63,1004,542-544,7-9', # 8 addresses
  237. 'seed_len': 192,
  238. 'dep_generators': {
  239. 'mmdat': 'walletgen4',
  240. 'mmbrain': 'walletgen4',
  241. 'addrs': 'addrgen4',
  242. 'rawtx': 'txcreate4',
  243. 'sigtx': 'txsign4',
  244. 'txdo': 'txdo4',
  245. },
  246. 'bw_filename': 'brainwallet.mmbrain',
  247. 'bw_params': '192,1',
  248. 'segwit': get_segwit_val()
  249. },
  250. '14': {
  251. 'kapasswd': 'Maxwell',
  252. 'tmpdir': os.path.join('test','tmp14'),
  253. 'wpasswd': 'The Halving',
  254. 'addr_idx_list': '61,998,502-504,7-9', # 8 addresses
  255. 'seed_len': 256,
  256. 'dep_generators': {
  257. 'mmdat': 'walletgen14',
  258. 'addrs': 'addrgen14',
  259. 'akeys.mmenc': 'keyaddrgen14',
  260. },
  261. 'segwit': get_segwit_val()
  262. },
  263. '5': {
  264. 'tmpdir': os.path.join('test','tmp5'),
  265. 'wpasswd': 'My changed password',
  266. 'hash_preset': '2',
  267. 'dep_generators': {
  268. 'mmdat': 'passchg',
  269. pwfile: 'passchg',
  270. },
  271. 'segwit': get_segwit_val()
  272. },
  273. '6': {
  274. 'name': 'reference wallet check (128-bit)',
  275. 'seed_len': 128,
  276. 'seed_id': 'FE3C6545',
  277. 'ref_bw_seed_id': '33F10310',
  278. 'addrfile_chk': {
  279. 'btc': ('B230 7526 638F 38CB','B64D 7327 EF2A 60FE'),
  280. 'ltc': ('2B23 5E97 848A B961','928D 3CB6 78FF 9829'),
  281. },
  282. 'addrfile_segwit_chk': {
  283. 'btc': ('9914 6D10 2307 F348','7DBF 441F E188 8B37'),
  284. 'ltc': ('CC09 A190 B7DF B7CD','3676 4C49 14F8 1AD0'),
  285. },
  286. 'addrfile_compressed_chk': {
  287. 'btc': ('95EB 8CC0 7B3B 7856','629D FDE4 CDC0 F276'),
  288. 'ltc': ('35D5 8ECA 9A42 46C3','37E9 A36E 94A2 010F'),
  289. },
  290. 'keyaddrfile_chk': {
  291. 'btc': ('CF83 32FB 8A8B 08E2','FEBF 7878 97BB CC35'),
  292. 'ltc': ('1896 A26C 7F14 2D01','B41D BA63 0605 DD66'),
  293. },
  294. 'keyaddrfile_segwit_chk': {
  295. 'btc': ('C13B F717 D4E8 CF59','4DB5 BAF0 45B7 6E81'),
  296. 'ltc': ('054B 9794 55B4 5D82','C373 0074 DEE6 B70A'),
  297. },
  298. 'keyaddrfile_compressed_chk': {
  299. 'btc': ('E43A FA46 5751 720A','B995 A6CF D1CD FAD0'),
  300. 'ltc': ('7603 2FE3 2145 FFAD','3248 356A C707 4A41'),
  301. },
  302. 'passfile_chk': 'EB29 DC4F 924B 289F',
  303. 'passfile32_chk': '37B6 C218 2ABC 7508',
  304. 'wpasswd': 'reference password',
  305. 'ref_wallet': 'FE3C6545-D782B529[128,1].mmdat',
  306. 'ic_wallet': 'FE3C6545-E29303EA-5E229E30[128,1].mmincog',
  307. 'ic_wallet_hex': 'FE3C6545-BC4BE3F2-32586837[128,1].mmincox',
  308. 'hic_wallet': 'FE3C6545-161E495F-BEB7548E[128,1].incog-offset123',
  309. 'hic_wallet_old': 'FE3C6545-161E495F-9860A85B[128,1].incog-old.offset123',
  310. 'tmpdir': os.path.join('test','tmp6'),
  311. 'kapasswd': '',
  312. 'addr_idx_list': '1010,500-501,31-33,1,33,500,1011', # 8 addresses
  313. 'pass_idx_list': '1,4,9-11,1100',
  314. 'dep_generators': {
  315. 'mmdat': 'refwalletgen1',
  316. pwfile: 'refwalletgen1',
  317. 'addrs': 'refaddrgen1',
  318. 'akeys.mmenc': 'refkeyaddrgen1'
  319. },
  320. 'segwit': get_segwit_val()
  321. },
  322. '7': {
  323. 'name': 'reference wallet check (192-bit)',
  324. 'seed_len': 192,
  325. 'seed_id': '1378FC64',
  326. 'ref_bw_seed_id': 'CE918388',
  327. 'addrfile_chk': {
  328. 'btc': ('8C17 A5FA 0470 6E89','0A59 C8CD 9439 8B81'),
  329. 'ltc': ('2B77 A009 D5D0 22AD','FCEC 0032 9EF9 B201'),
  330. },
  331. 'addrfile_segwit_chk': {
  332. 'btc': ('91C4 0414 89E4 2089','3BA6 7494 8E2B 858D'),
  333. 'ltc': ('8F12 FA7B 9F12 594C','E79E F55B 1536 56F2'),
  334. },
  335. 'addrfile_compressed_chk': {
  336. 'btc': ('2615 8401 2E98 7ECA','DF38 22AB AAB0 124E'),
  337. 'ltc': ('197C C48C 3C37 AB0F','5072 15DA 1A90 5E99'),
  338. },
  339. 'keyaddrfile_chk': {
  340. 'btc': ('9648 5132 B98E 3AD9','2F72 C83F 44C5 0FAC'),
  341. 'ltc': ('DBD4 FAB6 7E46 CD07','1DA9 C245 F669 670C'),
  342. },
  343. 'keyaddrfile_segwit_chk': {
  344. 'btc': ('C98B DF08 A3D5 204B','25F2 AEB6 AAAC 8BBE'),
  345. 'ltc': ('1829 7FE7 2567 CB91','1305 9007 E515 B66A'),
  346. },
  347. 'keyaddrfile_compressed_chk': {
  348. 'btc': ('6D6D 3D35 04FD B9C3','B345 9CD8 9EAE 5489'),
  349. 'ltc': ('F5DA 9D60 6798 C4E9','F928 113B C9D7 9DF5'),
  350. },
  351. 'passfile_chk': 'ADEA 0083 094D 489A',
  352. 'passfile32_chk': '2A28 C5C7 36EC 217A',
  353. 'wpasswd': 'reference password',
  354. 'ref_wallet': '1378FC64-6F0F9BB4[192,1].mmdat',
  355. 'ic_wallet': '1378FC64-2907DE97-F980D21F[192,1].mmincog',
  356. 'ic_wallet_hex': '1378FC64-4DCB5174-872806A7[192,1].mmincox',
  357. 'hic_wallet': '1378FC64-B55E9958-77256FC1[192,1].incog.offset123',
  358. 'hic_wallet_old': '1378FC64-B55E9958-D85FF20C[192,1].incog-old.offset123',
  359. 'tmpdir': os.path.join('test','tmp7'),
  360. 'kapasswd': '',
  361. 'addr_idx_list': '1010,500-501,31-33,1,33,500,1011', # 8 addresses
  362. 'pass_idx_list': '1,4,9-11,1100',
  363. 'dep_generators': {
  364. 'mmdat': 'refwalletgen2',
  365. pwfile: 'refwalletgen2',
  366. 'addrs': 'refaddrgen2',
  367. 'akeys.mmenc': 'refkeyaddrgen2'
  368. },
  369. 'segwit': get_segwit_val()
  370. },
  371. '8': {
  372. 'name': 'reference wallet check (256-bit)',
  373. 'seed_len': 256,
  374. 'seed_id': '98831F3A',
  375. 'ref_bw_seed_id': 'B48CD7FC',
  376. 'addrfile_chk': {
  377. 'btc': ('6FEF 6FB9 7B13 5D91','3C2C 8558 BB54 079E'),
  378. 'ltc': ('AD52 C3FE 8924 AAF0','5738 5C4F 167C F9AE'),
  379. },
  380. 'addrfile_segwit_chk': {
  381. 'btc': ('06C1 9C87 F25C 4EE6','58D1 7B6C E9F9 9C14'),
  382. 'ltc': ('63DF E42A 0827 21C3','1A3F 3016 2E2B F33A'),
  383. },
  384. 'addrfile_compressed_chk': {
  385. 'btc': ('A33C 4FDE F515 F5BC','5186 02C2 535E B7D5'),
  386. 'ltc': ('3FC0 8F03 C2D6 BD19','535E 5CDC 1CA7 08D5'),
  387. },
  388. 'keyaddrfile_chk': {
  389. 'btc': ('9F2D D781 1812 8BAD','7410 8F95 4B33 B4B2'),
  390. 'ltc': ('B804 978A 8796 3ED4','93A6 844C 8ECC BEF4'),
  391. },
  392. 'keyaddrfile_segwit_chk': {
  393. 'btc': ('A447 12C2 DD14 5A9B','0690 460D A600 D315'),
  394. 'ltc': ('E8A3 9F6E E164 A521','70ED 8557 5882 08A5'),
  395. },
  396. 'keyaddrfile_compressed_chk': {
  397. 'btc': ('420A 8EB5 A9E2 7814','3243 DD92 809E FE8D'),
  398. 'ltc': ('8D1C 781F EB7F 44BC','678E 8EF9 1396 B140'),
  399. },
  400. 'passfile_chk': '2D6D 8FBA 422E 1315',
  401. 'passfile32_chk': 'F6C1 CDFB 97D9 FCAE',
  402. 'wpasswd': 'reference password',
  403. 'ref_wallet': '98831F3A-{}[256,1].mmdat'.format(('27F2BF93','E2687906')[g.testnet]),
  404. 'ref_addrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.addrs'.format(altcoin_pfx,tn_ext),
  405. 'ref_segwitaddrfile':'98831F3A{}-S[1,31-33,500-501,1010-1011]{}.addrs'.format(altcoin_pfx,tn_ext),
  406. 'ref_keyaddrfile': '98831F3A{}[1,31-33,500-501,1010-1011]{}.akeys.mmenc'.format(altcoin_pfx,tn_ext),
  407. 'ref_passwdfile': '98831F3A-фубар@crypto.org-b58-20[1,4,9-11,1100].pws',
  408. 'ref_addrfile_chksum': {
  409. 'btc': ('6FEF 6FB9 7B13 5D91','3C2C 8558 BB54 079E'),
  410. 'ltc': ('AD52 C3FE 8924 AAF0','5738 5C4F 167C F9AE'),
  411. },
  412. 'ref_segwitaddrfile_chksum': {
  413. 'btc': ('06C1 9C87 F25C 4EE6','58D1 7B6C E9F9 9C14'),
  414. 'ltc': ('63DF E42A 0827 21C3','1A3F 3016 2E2B F33A'),
  415. },
  416. 'ref_keyaddrfile_chksum': {
  417. 'btc': ('9F2D D781 1812 8BAD','7410 8F95 4B33 B4B2'),
  418. 'ltc': ('B804 978A 8796 3ED4','93A6 844C 8ECC BEF4'),
  419. },
  420. 'ref_passwdfile_chksum': 'A983 DAB9 5514 27FB',
  421. # 'ref_fake_unspent_data':'98831F3A_unspent.json',
  422. 'ref_tx_file': {
  423. 'btc': 'FFB367[1.234]{}.rawtx',
  424. 'bch': '99BE60-BCH[106.6789]{}.rawtx',
  425. 'b2x': '6A52BC-B2X[106.6789,tl=1320969600]{}.rawtx',
  426. 'ltc': '75F455-LTC[106.6789]{}.rawtx',
  427. },
  428. 'ic_wallet': '98831F3A-5482381C-18460FB1[256,1].mmincog',
  429. 'ic_wallet_hex': '98831F3A-1630A9F2-870376A9[256,1].mmincox',
  430. 'hic_wallet': '98831F3A-F59B07A0-559CEF19[256,1].incog.offset123',
  431. 'hic_wallet_old': '98831F3A-F59B07A0-848535F3[256,1].incog-old.offset123',
  432. 'tmpdir': os.path.join('test','tmp8'),
  433. 'kapasswd': '',
  434. 'addr_idx_list': '1010,500-501,31-33,1,33,500,1011', # 8 addresses
  435. 'pass_idx_list': '1,4,9-11,1100',
  436. 'dep_generators': {
  437. 'mmdat': 'refwalletgen3',
  438. pwfile: 'refwalletgen3',
  439. 'addrs': 'refaddrgen3',
  440. 'akeys.mmenc': 'refkeyaddrgen3'
  441. },
  442. 'segwit': get_segwit_val()
  443. },
  444. '9': {
  445. 'tmpdir': os.path.join('test','tmp9'),
  446. 'tool_enc_infn': 'tool_encrypt.in',
  447. # 'tool_enc_ref_infn': 'tool_encrypt_ref.in',
  448. 'wpasswd': 'reference password',
  449. 'dep_generators': {
  450. 'tool_encrypt.in': 'tool_encrypt',
  451. 'tool_encrypt.in.mmenc': 'tool_encrypt',
  452. # 'tool_encrypt_ref.in': 'tool_encrypt_ref',
  453. # 'tool_encrypt_ref.in.mmenc': 'tool_encrypt_ref',
  454. },
  455. },
  456. }
  457. from copy import deepcopy
  458. for a,b in (('6','11'),('7','12'),('8','13')):
  459. cfgs[b] = deepcopy(cfgs[a])
  460. cfgs[b]['tmpdir'] = os.path.join('test','tmp'+b)
  461. from collections import OrderedDict
  462. cmd_group = OrderedDict()
  463. cmd_group['help'] = OrderedDict([
  464. # test description depends
  465. ['helpscreens', (1,'help screens', [],1)],
  466. ['longhelpscreens', (1,'help screens (--longhelp)',[],1)],
  467. ])
  468. cmd_group['dfl_wallet'] = OrderedDict([
  469. ['walletgen_dfl_wallet', (15,'wallet generation (default wallet)',[[[],15]],1)],
  470. ['export_seed_dfl_wallet',(15,'seed export to mmseed format (default wallet)',[[[pwfile],15]],1)],
  471. ['addrgen_dfl_wallet',(15,'address generation (default wallet)',[[[pwfile],15]],1)],
  472. ['txcreate_dfl_wallet',(15,'transaction creation (default wallet)',[[['addrs'],15]],1)],
  473. ['txsign_dfl_wallet',(15,'transaction signing (default wallet)',[[['rawtx',pwfile],15]],1)],
  474. ['passchg_dfl_wallet',(16,'password, label and hash preset change (default wallet)',[[[pwfile],15]],1)],
  475. ['walletchk_newpass_dfl_wallet',(16,'wallet check with new pw, label and hash preset',[[[pwfile],16]],1)],
  476. ['delete_dfl_wallet',(15,'delete default wallet',[[[pwfile],15]],1)],
  477. ])
  478. cmd_group['main'] = OrderedDict([
  479. ['walletgen', (1,'wallet generation', [[['del_dw_run'],15]],1)],
  480. # ['walletchk', (1,'wallet check', [[['mmdat'],1]])],
  481. ['passchg', (5,'password, label and hash preset change',[[['mmdat',pwfile],1]],1)],
  482. ['walletchk_newpass',(5,'wallet check with new pw, label and hash preset',[[['mmdat',pwfile],5]],1)],
  483. ['addrgen', (1,'address generation', [[['mmdat',pwfile],1]],1)],
  484. ['addrimport', (1,'address import', [[['addrs'],1]],1)],
  485. ['txcreate', (1,'transaction creation', [[['addrs'],1]],1)],
  486. ['txbump', (1,'transaction fee bumping (no send)',[[['rawtx'],1]],1)],
  487. ['txsign', (1,'transaction signing', [[['mmdat','rawtx',pwfile,'txbump'],1]],1)],
  488. ['txsend', (1,'transaction sending', [[['sigtx'],1]])],
  489. # txdo must go after txsign
  490. ['txdo', (1,'online transaction', [[['sigtx','mmdat'],1]])],
  491. ['export_hex', (1,'seed export to hexadecimal format', [[['mmdat'],1]])],
  492. ['export_seed', (1,'seed export to mmseed format', [[['mmdat'],1]])],
  493. ['export_mnemonic', (1,'seed export to mmwords format', [[['mmdat'],1]])],
  494. ['export_incog', (1,'seed export to mmincog format', [[['mmdat'],1]])],
  495. ['export_incog_hex',(1,'seed export to mmincog hex format', [[['mmdat'],1]])],
  496. ['export_incog_hidden',(1,'seed export to hidden mmincog format', [[['mmdat'],1]])],
  497. ['addrgen_hex', (1,'address generation from mmhex file', [[['mmhex','addrs'],1]])],
  498. ['addrgen_seed', (1,'address generation from mmseed file', [[['mmseed','addrs'],1]])],
  499. ['addrgen_mnemonic',(1,'address generation from mmwords file',[[['mmwords','addrs'],1]])],
  500. ['addrgen_incog', (1,'address generation from mmincog file',[[['mmincog','addrs'],1]])],
  501. ['addrgen_incog_hex',(1,'address generation from mmincog hex file',[[['mmincox','addrs'],1]])],
  502. ['addrgen_incog_hidden',(1,'address generation from hidden mmincog file', [[[hincog_fn,'addrs'],1]])],
  503. ['keyaddrgen', (1,'key-address file generation', [[['mmdat',pwfile],1]])],
  504. ['txsign_keyaddr',(1,'transaction signing with key-address file', [[['akeys.mmenc','rawtx'],1]])],
  505. ['walletgen2',(2,'wallet generation (2), 128-bit seed', [[['del_dw_run'],15]])],
  506. ['addrgen2', (2,'address generation (2)', [[['mmdat'],2]])],
  507. ['txcreate2', (2,'transaction creation (2)', [[['addrs'],2]])],
  508. ['txsign2', (2,'transaction signing, two transactions',[[['mmdat','rawtx'],1],[['mmdat','rawtx'],2]])],
  509. ['export_mnemonic2', (2,'seed export to mmwords format (2)',[[['mmdat'],2]])],
  510. ['walletgen3',(3,'wallet generation (3)', [[['del_dw_run'],15]])],
  511. ['addrgen3', (3,'address generation (3)', [[['mmdat'],3]])],
  512. ['txcreate3', (3,'tx creation with inputs and outputs from two wallets', [[['addrs'],1],[['addrs'],3]])],
  513. ['txsign3', (3,'tx signing with inputs and outputs from two wallets',[[['mmdat'],1],[['mmdat','rawtx'],3]])],
  514. ['walletgen14', (14,'wallet generation (14)', [[['del_dw_run'],15]],14)],
  515. ['addrgen14', (14,'address generation (14)', [[['mmdat'],14]])],
  516. ['keyaddrgen14',(14,'key-address file generation (14)', [[['mmdat'],14]],14)],
  517. ['walletgen4',(4,'wallet generation (4) (brainwallet)', [[['del_dw_run'],15]])],
  518. ['addrgen4', (4,'address generation (4)', [[['mmdat'],4]])],
  519. ['txcreate4', (4,'tx creation with inputs and outputs from four seed sources, key-address file and non-MMGen inputs and outputs', [[['addrs'],1],[['addrs'],2],[['addrs'],3],[['addrs'],4],[['addrs','akeys.mmenc'],14]])],
  520. ['txsign4', (4,'tx signing with inputs and outputs from incog file, mnemonic file, wallet, brainwallet, key-address file and non-MMGen inputs and outputs', [[['mmincog'],1],[['mmwords'],2],[['mmdat'],3],[['mmbrain','rawtx'],4],[['akeys.mmenc'],14]])],
  521. ['txdo4', (4,'tx creation,signing and sending with inputs and outputs from four seed sources, key-address file and non-MMGen inputs and outputs', [[['addrs'],1],[['addrs'],2],[['addrs'],3],[['addrs'],4],[['addrs','akeys.mmenc'],14],[['mmincog'],1],[['mmwords'],2],[['mmdat'],3],[['mmbrain','rawtx'],4],[['akeys.mmenc'],14]])], # must go after txsign4
  522. ['txbump4', (4,'tx fee bump + send with inputs and outputs from four seed sources, key-address file and non-MMGen inputs and outputs', [[['akeys.mmenc'],14],[['mmincog'],1],[['mmwords'],2],[['mmdat'],3],[['akeys.mmenc'],14],[['mmbrain','sigtx','mmdat','txdo'],4]])], # must go after txsign4
  523. ])
  524. cmd_group['tool'] = OrderedDict([
  525. ['tool_encrypt', (9,"'mmgen-tool encrypt' (random data)", [],1)],
  526. ['tool_decrypt', (9,"'mmgen-tool decrypt' (random data)", [[[cfgs['9']['tool_enc_infn'],cfgs['9']['tool_enc_infn']+'.mmenc'],9]],1)],
  527. # ['tool_encrypt_ref', (9,"'mmgen-tool encrypt' (reference text)", [])],
  528. ['tool_find_incog_data', (9,"'mmgen-tool find_incog_data'", [[[hincog_fn],1],[[incog_id_fn],1]])],
  529. # ['pywallet', (9,"'mmgen-pywallet'", [],1)],
  530. ])
  531. # saved reference data
  532. cmd_group['ref'] = (
  533. # reading
  534. ('ref_wallet_chk', ([],'saved reference wallet')),
  535. ('ref_seed_chk', ([],'saved seed file')),
  536. ('ref_hex_chk', ([],'saved mmhex file')),
  537. ('ref_mn_chk', ([],'saved mnemonic file')),
  538. ('ref_hincog_chk', ([],'saved hidden incog reference wallet')),
  539. ('ref_brain_chk', ([],'saved brainwallet')),
  540. # generating new reference ('abc' brainwallet) files:
  541. ('refwalletgen', ([],'gen new refwallet')),
  542. ('refaddrgen', (['mmdat',pwfile],'new refwallet addr chksum')),
  543. ('refkeyaddrgen', (['mmdat',pwfile],'new refwallet key-addr chksum')),
  544. ('refaddrgen_compressed', (['mmdat',pwfile],'new refwallet addr chksum (compressed)')),
  545. ('refkeyaddrgen_compressed', (['mmdat',pwfile],'new refwallet key-addr chksum (compressed)')),
  546. ('refpasswdgen', (['mmdat',pwfile],'new refwallet passwd file chksum')),
  547. ('ref_b32passwdgen',(['mmdat',pwfile],'new refwallet passwd file chksum (base32)')),
  548. )
  549. # misc. saved reference data
  550. cmd_group['ref_other'] = (
  551. ('ref_addrfile_chk', 'saved reference address file'),
  552. ('ref_segwitaddrfile_chk','saved reference address file (segwit)'),
  553. ('ref_keyaddrfile_chk','saved reference key-address file'),
  554. ('ref_passwdfile_chk', 'saved reference password file'),
  555. # Create the fake inputs:
  556. # ('txcreate8', 'transaction creation (8)'),
  557. ('ref_tx_chk', 'saved reference tx file'),
  558. ('ref_brain_chk_spc3', 'saved brainwallet (non-standard spacing)'),
  559. ('ref_tool_decrypt', 'decryption of saved MMGen-encrypted file'),
  560. )
  561. # mmgen-walletconv:
  562. cmd_group['conv_in'] = ( # reading
  563. ('ref_wallet_conv', 'conversion of saved reference wallet'),
  564. ('ref_mn_conv', 'conversion of saved mnemonic'),
  565. ('ref_seed_conv', 'conversion of saved seed file'),
  566. ('ref_hex_conv', 'conversion of saved hexadecimal seed file'),
  567. ('ref_brain_conv', 'conversion of ref brainwallet'),
  568. ('ref_incog_conv', 'conversion of saved incog wallet'),
  569. ('ref_incox_conv', 'conversion of saved hex incog wallet'),
  570. ('ref_hincog_conv', 'conversion of saved hidden incog wallet'),
  571. ('ref_hincog_conv_old','conversion of saved hidden incog wallet (old format)')
  572. )
  573. cmd_group['conv_out'] = ( # writing
  574. ('ref_wallet_conv_out', 'ref seed conversion to wallet'),
  575. ('ref_mn_conv_out', 'ref seed conversion to mnemonic'),
  576. ('ref_hex_conv_out', 'ref seed conversion to hex seed'),
  577. ('ref_seed_conv_out', 'ref seed conversion to seed'),
  578. ('ref_incog_conv_out', 'ref seed conversion to incog data'),
  579. ('ref_incox_conv_out', 'ref seed conversion to hex incog data'),
  580. ('ref_hincog_conv_out', 'ref seed conversion to hidden incog data')
  581. )
  582. cmd_group['regtest'] = (
  583. ('regtest_setup', 'regtest (Bob and Alice) mode setup'),
  584. ('regtest_walletgen_bob', 'wallet generation (Bob)'),
  585. ('regtest_walletgen_alice', 'wallet generation (Alice)'),
  586. ('regtest_addrgen_bob', 'address generation (Bob)'),
  587. ('regtest_addrgen_alice', 'address generation (Alice)'),
  588. ('regtest_addrimport_bob', "importing Bob's addresses"),
  589. ('regtest_addrimport_alice', "importing Alice's addresses"),
  590. ('regtest_fund_bob', "funding Bob's wallet"),
  591. ('regtest_fund_alice', "funding Alice's wallet"),
  592. ('regtest_bob_bal1', "Bob's balance"),
  593. ('regtest_bob_split1', "splitting Bob's funds"),
  594. ('regtest_generate', 'mining a block'),
  595. ('regtest_bob_bal2', "Bob's balance"),
  596. ('regtest_bob_rbf_send', 'sending funds to Alice (RBF)'),
  597. ('regtest_get_mempool1', 'mempool (before RBF bump)'),
  598. ('regtest_bob_rbf_bump', 'bumping RBF transaction'),
  599. ('regtest_get_mempool2', 'mempool (after RBF bump)'),
  600. ('regtest_generate', 'mining a block'),
  601. ('regtest_bob_bal3', "Bob's balance"),
  602. ('regtest_bob_pre_import', 'sending to non-imported address'),
  603. ('regtest_generate', 'mining a block'),
  604. ('regtest_bob_import_addr', 'importing non-MMGen address with --rescan'),
  605. ('regtest_bob_bal4', "Bob's balance (after import with rescan)"),
  606. ('regtest_bob_import_list', 'importing flat address list'),
  607. ('regtest_bob_split2', "splitting Bob's funds"),
  608. ('regtest_generate', 'mining a block'),
  609. ('regtest_bob_bal5', "Bob's balance"),
  610. ('regtest_bob_send_non_mmgen', 'sending funds to Alice (from non-MMGen addrs)'),
  611. ('regtest_generate', 'mining a block'),
  612. ('regtest_bob_alice_bal', "Bob and Alice's balances"),
  613. ('regtest_alice_add_label1', 'adding a label'),
  614. ('regtest_alice_chk_label1', 'the label'),
  615. ('regtest_alice_add_label2', 'adding a label'),
  616. ('regtest_alice_chk_label2', 'the label'),
  617. ('regtest_alice_edit_label1', 'editing a label'),
  618. ('regtest_alice_chk_label3', 'the label'),
  619. ('regtest_alice_remove_label1','removing a label'),
  620. ('regtest_alice_chk_label4', 'the label'),
  621. ('regtest_stop', 'stopping regtest daemon'),
  622. )
  623. cmd_group['regtest_split'] = (
  624. ('regtest_split_setup', 'regtest forking scenario setup'),
  625. ('regtest_walletgen_bob', "generating Bob's wallet"),
  626. ('regtest_addrgen_bob', "generating Bob's addresses"),
  627. ('regtest_addrimport_bob', "importing Bob's addresses"),
  628. ('regtest_fund_bob', "funding Bob's wallet"),
  629. ('regtest_split_fork', 'regtest split fork'),
  630. ('regtest_split_start_btc', 'start regtest daemon (BTC)'),
  631. ('regtest_split_start_b2x', 'start regtest daemon (B2X)'),
  632. ('regtest_split_gen_btc', 'mining a block (BTC)'),
  633. ('regtest_split_gen_b2x', 'mining 100 blocks (B2X)'),
  634. ('regtest_split_do_split', 'creating coin splitting transactions'),
  635. ('regtest_split_sign_b2x', 'signing B2X split transaction'),
  636. ('regtest_split_sign_btc', 'signing BTC split transaction'),
  637. ('regtest_split_send_b2x', 'sending B2X split transaction'),
  638. ('regtest_split_send_btc', 'sending BTC split transaction'),
  639. ('regtest_split_gen_btc', 'mining a block (BTC)'),
  640. ('regtest_split_gen_b2x2', 'mining a block (B2X)'),
  641. ('regtest_split_txdo_timelock_bad_btc', 'sending transaction with bad locktime (BTC)'),
  642. ('regtest_split_txdo_timelock_good_btc','sending transaction with good locktime (BTC)'),
  643. ('regtest_split_txdo_timelock_bad_b2x', 'sending transaction with bad locktime (B2X)'),
  644. ('regtest_split_txdo_timelock_good_b2x','sending transaction with good locktime (B2X)'),
  645. )
  646. cmd_group['misc'] = (
  647. ('autosign', 'transaction autosigning (BTC,BCH,LTC)'),
  648. )
  649. # undocumented admin cmds
  650. cmd_group_admin = OrderedDict()
  651. cmd_group_admin['create_ref_tx'] = (
  652. ('ref_tx_setup', 'regtest (Bob and Alice) mode setup'),
  653. ('ref_tx_addrgen_bob_ref_wallet', 'address generation (Bob - reference wallet)'),
  654. ('ref_tx_addrimport_bob_ref_wallet', "importing Bob's addresses (reference wallet)"),
  655. ('ref_tx_fund_bob', "funding Bob's wallet (reference wallet)"),
  656. ('ref_tx_bob_split', "splitting Bob's funds (reference wallet)"),
  657. ('ref_tx_generate', 'mining a block'),
  658. ('ref_tx_bob_create_tx', "creating reference transaction"),
  659. ('ref_tx_bob_modify_tx', "modifying reference transaction (testnet+mainnet)"),
  660. )
  661. cmd_list_admin = OrderedDict()
  662. cmd_data_admin = OrderedDict()
  663. for k in cmd_group_admin: cmd_list_admin[k] = []
  664. cmd_data_admin['info_create_ref_tx'] = 'create reference tx',[8]
  665. for a,b in cmd_group_admin['create_ref_tx']:
  666. cmd_list_admin['create_ref_tx'].append(a)
  667. cmd_data_admin[a] = (8,b,[[[],8]])
  668. # end undocumented admin commands
  669. cmd_list = OrderedDict()
  670. for k in cmd_group: cmd_list[k] = []
  671. cmd_data = OrderedDict()
  672. for k,v in (
  673. ('help', ('help screens',[])),
  674. ('dfl_wallet', ('basic operations with default wallet',[15,16])),
  675. ('main', ('basic operations',[1,2,3,4,5,15,16])),
  676. ('tool', ('tools',[9]))
  677. ):
  678. cmd_data['info_'+k] = v
  679. for i in cmd_group[k]:
  680. cmd_list[k].append(i)
  681. cmd_data[i] = cmd_group[k][i]
  682. cmd_data['info_ref'] = 'reference data',[6,7,8]
  683. for a,b in cmd_group['ref']:
  684. for i,j in ((1,128),(2,192),(3,256)):
  685. k = a+str(i)
  686. cmd_list['ref'].append(k)
  687. cmd_data[k] = (5+i,'%s (%s-bit)' % (b[1],j),[[b[0],5+i]])
  688. cmd_data['info_ref_other'] = 'other reference data',[8]
  689. for a,b in cmd_group['ref_other']:
  690. cmd_list['ref_other'].append(a)
  691. cmd_data[a] = (8,b,[[[],8]])
  692. cmd_data['info_conv_in'] = 'wallet conversion from reference data',[11,12,13]
  693. for a,b in cmd_group['conv_in']:
  694. for i,j in ((1,128),(2,192),(3,256)):
  695. k = a+str(i)
  696. cmd_list['conv_in'].append(k)
  697. cmd_data[k] = (10+i,'%s (%s-bit)' % (b,j),[[[],10+i]])
  698. cmd_data['info_conv_out'] = 'wallet conversion to reference data',[11,12,13]
  699. for a,b in cmd_group['conv_out']:
  700. for i,j in ((1,128),(2,192),(3,256)):
  701. k = a+str(i)
  702. cmd_list['conv_out'].append(k)
  703. cmd_data[k] = (10+i,'%s (%s-bit)' % (b,j),[[[],10+i]])
  704. cmd_data['info_regtest'] = 'regtest mode',[17]
  705. for a,b in cmd_group['regtest']:
  706. cmd_list['regtest'].append(a)
  707. cmd_data[a] = (17,b,[[[],17]])
  708. cmd_data['info_regtest_split'] = 'regtest mode with fork and coin split',[17]
  709. for a,b in cmd_group['regtest_split']:
  710. cmd_list['regtest_split'].append(a)
  711. cmd_data[a] = (19,b,[[[],19]])
  712. cmd_data['info_misc'] = 'miscellaneous operations',[18]
  713. for a,b in cmd_group['misc']:
  714. cmd_list['misc'].append(a)
  715. cmd_data[a] = (18,b,[[[],18]])
  716. utils = {
  717. 'check_deps': 'check dependencies for specified command',
  718. 'clean': 'clean specified tmp dir(s) 1,2,3,4,5 or 6 (no arg = all dirs)',
  719. }
  720. addrs_per_wallet = 8
  721. meta_cmds = OrderedDict([
  722. ['ref1', ('refwalletgen1','refaddrgen1','refkeyaddrgen1')],
  723. ['ref2', ('refwalletgen2','refaddrgen2','refkeyaddrgen2')],
  724. ['ref3', ('refwalletgen3','refaddrgen3','refkeyaddrgen3')],
  725. ['gen', ('walletgen','addrgen')],
  726. ['pass', ('passchg','walletchk_newpass')],
  727. ['tx', ('addrimport','txcreate','txsign','txsend')],
  728. ['export', [k for k in cmd_data if k[:7] == 'export_' and cmd_data[k][0] == 1]],
  729. ['gen_sp', [k for k in cmd_data if k[:8] == 'addrgen_' and cmd_data[k][0] == 1]],
  730. ['online', ('keyaddrgen','txsign_keyaddr')],
  731. ['2', [k for k in cmd_data if cmd_data[k][0] == 2]],
  732. ['3', [k for k in cmd_data if cmd_data[k][0] == 3]],
  733. ['4', [k for k in cmd_data if cmd_data[k][0] == 4]],
  734. ['saved_ref1', [c[0]+'1' for c in cmd_group['ref']]],
  735. ['saved_ref2', [c[0]+'2' for c in cmd_group['ref']]],
  736. ['saved_ref3', [c[0]+'3' for c in cmd_group['ref']]],
  737. ['saved_ref_other', [c[0] for c in cmd_group['ref_other']]],
  738. ['saved_ref_conv_in1', [c[0]+'1' for c in cmd_group['conv_in']]],
  739. ['saved_ref_conv_in2', [c[0]+'2' for c in cmd_group['conv_in']]],
  740. ['saved_ref_conv_in3', [c[0]+'3' for c in cmd_group['conv_in']]],
  741. ['saved_ref_conv_out1', [c[0]+'1' for c in cmd_group['conv_out']]],
  742. ['saved_ref_conv_out2', [c[0]+'2' for c in cmd_group['conv_out']]],
  743. ['saved_ref_conv_out3', [c[0]+'3' for c in cmd_group['conv_out']]],
  744. ['regtest', dict(cmd_group['regtest']).keys()],
  745. ])
  746. del cmd_group
  747. if opt.profile: opt.names = True
  748. if opt.resume: opt.skip_deps = True
  749. if opt.log:
  750. log_fd = open(log_file,'a')
  751. log_fd.write('\nLog started: %s\n' % make_timestr())
  752. usr_rand_chars = (5,30)[bool(opt.usr_random)]
  753. usr_rand_arg = '-r%s' % usr_rand_chars
  754. cmd_total = 0
  755. # Disable color in spawned scripts so we can parse their output
  756. os.environ['MMGEN_DISABLE_COLOR'] = '1'
  757. os.environ['MMGEN_NO_LICENSE'] = '1'
  758. os.environ['MMGEN_MIN_URANDCHARS'] = '3'
  759. os.environ['MMGEN_BOGUS_SEND'] = '1'
  760. def get_segwit_arg(cfg): return ([],['--type','segwit'])[cfg['segwit']]
  761. # Tell spawned programs they're running in the test suite
  762. os.environ['MMGEN_TEST_SUITE'] = '1'
  763. if opt.debug_scripts: os.environ['MMGEN_DEBUG'] = '1'
  764. if opt.exact_output:
  765. def msg(s): pass
  766. vmsg = vmsg_r = msg_r = msg
  767. else:
  768. def msg(s): sys.stderr.write(s+'\n')
  769. def vmsg(s):
  770. if opt.verbose: sys.stderr.write(s+'\n')
  771. def msg_r(s): sys.stderr.write(s)
  772. def vmsg_r(s):
  773. if opt.verbose: sys.stderr.write(s)
  774. stderr_save = sys.stderr
  775. def silence():
  776. if not (opt.verbose or opt.exact_output):
  777. f = ('/dev/null','stderr.out')[g.platform=='win']
  778. sys.stderr = open(f,'a')
  779. def end_silence():
  780. if not (opt.verbose or opt.exact_output):
  781. sys.stderr = stderr_save
  782. def errmsg(s): stderr_save.write(s+'\n')
  783. def errmsg_r(s): stderr_save.write(s)
  784. if opt.list_cmds:
  785. fs = ' {:<{w}} - {}'
  786. Msg(green('AVAILABLE COMMANDS:'))
  787. w = max([len(i) for i in cmd_data])
  788. for cmd in cmd_data:
  789. if cmd[:5] == 'info_':
  790. m = capfirst(cmd_data[cmd][0])
  791. Msg(green(' %s:' % m))
  792. continue
  793. Msg(' '+fs.format(cmd,cmd_data[cmd][1],w=w))
  794. w = max([len(i) for i in meta_cmds])
  795. Msg(green('\nAVAILABLE METACOMMANDS:'))
  796. for cmd in meta_cmds:
  797. Msg(fs.format(cmd,' '.join(meta_cmds[cmd]),w=w))
  798. w = max([len(i) for i in cmd_list])
  799. Msg(green('\nAVAILABLE COMMAND GROUPS:'))
  800. for g in cmd_list:
  801. Msg(fs.format(g,' '.join(cmd_list[g]),w=w))
  802. Msg(green('\nAVAILABLE UTILITIES:'))
  803. w = max([len(i) for i in utils])
  804. for cmd in sorted(utils):
  805. Msg(fs.format(cmd,utils[cmd],w=w))
  806. sys.exit(0)
  807. NL = ('\r\n','\n')[g.platform=='linux' and bool(opt.popen_spawn)]
  808. def get_file_with_ext(ext,mydir,delete=True,no_dot=False,return_list=False):
  809. dot = ('.','')[bool(no_dot)]
  810. flist = [os.path.join(mydir,f) for f in os.listdir(mydir)
  811. if f == ext or f[-len(dot+ext):] == dot+ext]
  812. if not flist: return False
  813. if return_list: return flist
  814. if len(flist) > 1:
  815. if delete:
  816. if not opt.quiet:
  817. msg("Multiple *.{} files in '{}' - deleting".format(ext,mydir))
  818. for f in flist:
  819. msg(f)
  820. os.unlink(f)
  821. return False
  822. else:
  823. return flist[0]
  824. def find_generated_exts(cmd):
  825. out = []
  826. for k in cfgs:
  827. for ext,prog in cfgs[k]['dep_generators'].items():
  828. if prog == cmd:
  829. out.append((ext,cfgs[k]['tmpdir']))
  830. return out
  831. def get_addrfile_checksum(display=False):
  832. addrfile = get_file_with_ext('addrs',cfg['tmpdir'])
  833. silence()
  834. chk = AddrList(addrfile).chksum
  835. if opt.verbose and display: msg('Checksum: %s' % cyan(chk))
  836. end_silence()
  837. return chk
  838. def verify_checksum_or_exit(checksum,chk):
  839. if checksum != chk:
  840. errmsg(red('Checksum error: %s' % chk))
  841. sys.exit(1)
  842. vmsg(green('Checksums match: %s') % (cyan(chk)))
  843. from test.mmgen_pexpect import MMGenPexpect
  844. class MMGenExpect(MMGenPexpect):
  845. def __init__(self,name,mmgen_cmd,cmd_args=[],extra_desc='',no_output=False,msg_only=False):
  846. desc = ((cmd_data[name][1],name)[bool(opt.names)] + (' ' + extra_desc)).strip()
  847. passthru_args = ['testnet','rpc_host','rpc_port','regtest','coin']
  848. if not opt.system:
  849. os.environ['PYTHONPATH'] = repo_root
  850. mmgen_cmd = os.path.relpath(os.path.join(repo_root,'cmds',mmgen_cmd))
  851. elif g.platform == 'win':
  852. mmgen_cmd = os.path.join('/mingw64','opt','bin',mmgen_cmd)
  853. return MMGenPexpect.__init__(
  854. self,
  855. name,
  856. mmgen_cmd,
  857. cmd_args,
  858. desc,
  859. no_output=no_output,
  860. passthru_args=passthru_args,
  861. msg_only=msg_only)
  862. def create_fake_unspent_entry(coinaddr,al_id=None,idx=None,lbl=None,non_mmgen=False,segwit=False):
  863. if 'S' not in g.proto.mmtypes: segwit = False
  864. if lbl: lbl = ' ' + lbl
  865. spk1,spk2 = (('76a914','88ac'),('a914','87'))[segwit and coinaddr.addr_fmt=='p2sh']
  866. amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[coin_sel]
  867. return {
  868. 'account': '{}:{}'.format(g.proto.base_coin.lower(),coinaddr) if non_mmgen \
  869. else (u'{}:{}{}'.format(al_id,idx,lbl.decode('utf8'))),
  870. 'vout': int(getrandnum(4) % 8),
  871. 'txid': hexlify(os.urandom(32)).decode('utf8'),
  872. 'amount': g.proto.coin_amt('%s.%s' % (amt1+(getrandnum(4) % amt2), getrandnum(4) % 100000000)),
  873. 'address': coinaddr,
  874. 'spendable': False,
  875. 'scriptPubKey': '{}{}{}'.format(spk1,coinaddr.hex,spk2),
  876. 'confirmations': getrandnum(4) % 50000
  877. }
  878. labels = [
  879. "Automotive",
  880. "Travel expenses",
  881. "Healthcare",
  882. "Freelancing 1",
  883. "Freelancing 2",
  884. "Alice's allowance",
  885. "Bob's bequest",
  886. "House purchase",
  887. "Real estate fund",
  888. "Job 1",
  889. "XYZ Corp.",
  890. "Eddie's endowment",
  891. "Emergency fund",
  892. "Real estate fund",
  893. "Ian's inheritance",
  894. "",
  895. "Rainy day",
  896. "Fred's funds",
  897. "Job 2",
  898. "Carl's capital",
  899. ]
  900. label_iter = None
  901. def create_fake_unspent_data(adata,tx_data,non_mmgen_input=''):
  902. out = []
  903. for d in tx_data.values():
  904. al = adata.addrlist(d['al_id'])
  905. for n,(idx,coinaddr) in enumerate(al.addrpairs()):
  906. while True:
  907. try: lbl = next(label_iter)
  908. except: label_iter = iter(labels)
  909. else: break
  910. out.append(create_fake_unspent_entry(coinaddr,d['al_id'],idx,lbl,segwit=d['segwit']))
  911. if n == 0: # create a duplicate address. This means addrs_per_wallet += 1
  912. out.append(create_fake_unspent_entry(coinaddr,d['al_id'],idx,lbl,segwit=d['segwit']))
  913. if non_mmgen_input:
  914. privkey = PrivKey(os.urandom(32),compressed=True)
  915. coinaddr = AddrGenerator('p2pkh').to_addr(KeyGenerator().to_pubhex(privkey))
  916. of = os.path.join(cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
  917. write_data_to_file(of,privkey.wif+'\n','compressed {} key'.format(g.proto.name),silent=True)
  918. out.append(create_fake_unspent_entry(coinaddr,non_mmgen=True,segwit=False))
  919. # msg('\n'.join([repr(o) for o in out])); sys.exit(0)
  920. return out
  921. def write_fake_data_to_file(d):
  922. unspent_data_file = os.path.join(cfg['tmpdir'],'unspent.json')
  923. write_data_to_file(unspent_data_file,d,'Unspent outputs',silent=True)
  924. os.environ['MMGEN_BOGUS_WALLET_DATA'] = unspent_data_file
  925. bwd_msg = 'MMGEN_BOGUS_WALLET_DATA=%s' % unspent_data_file
  926. if opt.print_cmdline: msg(bwd_msg)
  927. if opt.log: log_fd.write(bwd_msg + ' ')
  928. if opt.verbose or opt.exact_output:
  929. sys.stderr.write("Fake transaction wallet data written to file '%s'\n" % unspent_data_file)
  930. def create_tx_data(sources):
  931. tx_data,ad = {},AddrData()
  932. for s in sources:
  933. afile = get_file_with_ext('addrs',cfgs[s]['tmpdir'])
  934. al = AddrList(afile)
  935. ad.add(al)
  936. aix = AddrIdxList(fmt_str=cfgs[s]['addr_idx_list'])
  937. if len(aix) != addrs_per_wallet:
  938. errmsg(red('Address index list length != %s: %s' %
  939. (addrs_per_wallet,repr(aix))))
  940. sys.exit(0)
  941. tx_data[s] = {
  942. 'addrfile': afile,
  943. 'chk': al.chksum,
  944. 'al_id': al.al_id,
  945. 'addr_idxs': aix[-2:],
  946. 'segwit': cfgs[s]['segwit']
  947. }
  948. return ad,tx_data
  949. def make_txcreate_cmdline(tx_data):
  950. privkey = PrivKey(os.urandom(32),compressed=True)
  951. t = ('p2pkh','segwit')['S' in g.proto.mmtypes]
  952. coinaddr = AddrGenerator(t).to_addr(KeyGenerator().to_pubhex(privkey))
  953. # total of two outputs must be < 10 BTC (<1000 LTC)
  954. mods = {'btc':(6,4),'bch':(6,4),'ltc':(600,400)}[coin_sel]
  955. for k in cfgs:
  956. cfgs[k]['amts'] = [None,None]
  957. for idx,mod in enumerate(mods):
  958. cfgs[k]['amts'][idx] = '%s.%s' % ((getrandnum(4) % mod), str(getrandnum(4))[:5])
  959. cmd_args = ['-d',cfg['tmpdir']]
  960. for num in tx_data:
  961. s = tx_data[num]
  962. cmd_args += [
  963. '{}:{},{}'.format(s['al_id'],s['addr_idxs'][0],cfgs[num]['amts'][0]),
  964. ]
  965. # + one change address and one BTC address
  966. if num is tx_data.keys()[-1]:
  967. cmd_args += ['{}:{}'.format(s['al_id'],s['addr_idxs'][1])]
  968. cmd_args += ['{},{}'.format(coinaddr,cfgs[num]['amts'][1])]
  969. return cmd_args + [tx_data[num]['addrfile'] for num in tx_data]
  970. def add_comments_to_addr_file(addrfile,outfile):
  971. silence()
  972. msg(green("Adding comments to address file '%s'" % addrfile))
  973. a = AddrList(addrfile)
  974. for n,idx in enumerate(a.idxs(),1):
  975. if n % 2: a.set_comment(idx,'Test address %s' % n)
  976. a.format(enable_comments=True)
  977. write_data_to_file(outfile,a.fmt_data,silent=True)
  978. end_silence()
  979. def make_brainwallet_file(fn):
  980. # Print random words with random whitespace in between
  981. from mmgen.mn_tirosh import words
  982. wl = words.split()
  983. nwords,ws_list,max_spaces = 10,' \n',5
  984. def rand_ws_seq():
  985. nchars = getrandnum(1) % max_spaces + 1
  986. return ''.join([ws_list[getrandnum(1)%len(ws_list)] for i in range(nchars)])
  987. rand_pairs = [wl[getrandnum(4) % len(wl)] + rand_ws_seq() for i in range(nwords)]
  988. d = ''.join(rand_pairs).rstrip() + '\n'
  989. if opt.verbose: msg_r('Brainwallet password:\n%s' % cyan(d))
  990. write_data_to_file(fn,d,'brainwallet password',silent=True)
  991. def do_between():
  992. if opt.pause:
  993. if keypress_confirm(green('Continue?'),default_yes=True):
  994. if opt.verbose or opt.exact_output: sys.stderr.write('\n')
  995. else:
  996. errmsg('Exiting at user request')
  997. sys.exit(0)
  998. elif opt.verbose or opt.exact_output:
  999. sys.stderr.write('\n')
  1000. rebuild_list = OrderedDict()
  1001. def check_needs_rerun(
  1002. ts,
  1003. cmd,
  1004. build=False,
  1005. root=True,
  1006. force_delete=False,
  1007. dpy=False
  1008. ):
  1009. rerun = (False,True)[root] # force_delete is not passed to recursive call
  1010. fns = []
  1011. if force_delete or not root:
  1012. # does cmd produce a needed dependency(ies)?
  1013. ret = ts.get_num_exts_for_cmd(cmd,dpy)
  1014. if ret:
  1015. for ext in ret[1]:
  1016. fn = get_file_with_ext(ext,cfgs[ret[0]]['tmpdir'],delete=build)
  1017. if fn:
  1018. if force_delete: os.unlink(fn)
  1019. else: fns.append(fn)
  1020. else: rerun = True
  1021. fdeps = ts.generate_file_deps(cmd)
  1022. cdeps = ts.generate_cmd_deps(fdeps)
  1023. # print 'cmd,fdeps,cdeps,fns: ',cmd,fdeps,cdeps,fns # DEBUG
  1024. for fn in fns:
  1025. my_age = os.stat(fn).st_mtime
  1026. for num,ext in fdeps:
  1027. f = get_file_with_ext(ext,cfgs[num]['tmpdir'],delete=build)
  1028. if f and os.stat(f).st_mtime > my_age:
  1029. rerun = True
  1030. for cdep in cdeps:
  1031. if check_needs_rerun(ts,cdep,build=build,root=False,dpy=cmd):
  1032. rerun = True
  1033. if build:
  1034. if rerun:
  1035. for fn in fns:
  1036. if not root: os.unlink(fn)
  1037. if not (dpy and opt.skip_deps):
  1038. ts.do_cmd(cmd)
  1039. if not root: do_between()
  1040. else:
  1041. # If prog produces multiple files:
  1042. if cmd not in rebuild_list or rerun == True:
  1043. rebuild_list[cmd] = (rerun,fns[0] if fns else '') # FIX
  1044. return rerun
  1045. def refcheck(desc,chk,refchk):
  1046. vmsg("Comparing %s '%s' to stored reference" % (desc,chk))
  1047. if chk == refchk:
  1048. ok()
  1049. else:
  1050. if not opt.verbose: errmsg('')
  1051. errmsg(red("""
  1052. Fatal error - %s '%s' does not match reference value '%s'. Aborting test
  1053. """.strip() % (desc,chk,refchk)))
  1054. sys.exit(3)
  1055. def check_deps(cmds):
  1056. if len(cmds) != 1:
  1057. die(1,'Usage: %s check_deps <command>' % g.prog_name)
  1058. cmd = cmds[0]
  1059. if cmd not in cmd_data:
  1060. die(1,"'%s': unrecognized command" % cmd)
  1061. if not opt.quiet:
  1062. msg("Checking dependencies for '%s'" % (cmd))
  1063. check_needs_rerun(ts,cmd,build=False)
  1064. w = max(len(i) for i in rebuild_list) + 1
  1065. for cmd in rebuild_list:
  1066. c = rebuild_list[cmd]
  1067. m = 'Rebuild' if (c[0] and c[1]) else 'Build' if c[0] else 'OK'
  1068. msg('cmd {:<{w}} {}'.format(cmd+':', m, w=w))
  1069. # mmsg(cmd,c)
  1070. def clean(usr_dirs=[]):
  1071. if opt.skip_deps: return
  1072. all_dirs = MMGenTestSuite().list_tmp_dirs()
  1073. dirs = (usr_dirs or all_dirs)
  1074. for d in sorted(dirs):
  1075. if str(d) in all_dirs:
  1076. cleandir(all_dirs[str(d)])
  1077. else:
  1078. die(1,'%s: invalid directory number' % d)
  1079. cleandir(os.path.join('test','data_dir'))
  1080. class MMGenTestSuite(object):
  1081. def __init__(self):
  1082. pass
  1083. def list_tmp_dirs(self):
  1084. d = {}
  1085. for k in cfgs: d[k] = cfgs[k]['tmpdir']
  1086. return d
  1087. def get_num_exts_for_cmd(self,cmd,dpy=False): # dpy ignored here
  1088. num = str(cmd_data[cmd][0])
  1089. dgl = cfgs[num]['dep_generators']
  1090. # mmsg(num,cmd,dgl)
  1091. if cmd in dgl.values():
  1092. exts = [k for k in dgl if dgl[k] == cmd]
  1093. return (num,exts)
  1094. else:
  1095. return None
  1096. def do_cmd(self,cmd):
  1097. # delete files produced by this cmd
  1098. # for ext,tmpdir in find_generated_exts(cmd):
  1099. # print cmd, get_file_with_ext(ext,tmpdir)
  1100. d = [(str(num),ext) for exts,num in cmd_data[cmd][2] for ext in exts]
  1101. # delete files depended on by this cmd
  1102. al = [get_file_with_ext(ext,cfgs[num]['tmpdir']) for num,ext in d]
  1103. global cfg
  1104. cfg = cfgs[str(cmd_data[cmd][0])]
  1105. if opt.resume:
  1106. if cmd == opt.resume:
  1107. msg(yellow("Resuming at '%s'" % cmd))
  1108. opt.resume = False
  1109. opt.skip_deps = False
  1110. else:
  1111. return
  1112. if opt.profile: start = time.time()
  1113. self.__class__.__dict__[cmd](*([self,cmd] + al))
  1114. if opt.profile:
  1115. msg('\r\033[50C{:.4f}'.format(time.time() - start))
  1116. global cmd_total
  1117. cmd_total += 1
  1118. def generate_file_deps(self,cmd):
  1119. return [(str(n),e) for exts,n in cmd_data[cmd][2] for e in exts]
  1120. def generate_cmd_deps(self,fdeps):
  1121. return [cfgs[str(n)]['dep_generators'][ext] for n,ext in fdeps]
  1122. def helpscreens(self,name,arg='--help'):
  1123. scripts = (
  1124. 'walletgen','walletconv','walletchk','txcreate','txsign','txsend','txdo','txbump',
  1125. 'addrgen','addrimport','keygen','passchg','tool','passgen','regtest','autosign')
  1126. for s in scripts:
  1127. t = MMGenExpect(name,('mmgen-'+s),[arg],extra_desc='(mmgen-%s)'%s,no_output=True)
  1128. t.read()
  1129. t.ok()
  1130. def longhelpscreens(self,name): self.helpscreens(name,arg='--longhelp')
  1131. def walletgen(self,name,del_dw_run='dummy',seed_len=None,gen_dfl_wallet=False):
  1132. write_to_tmpfile(cfg,pwfile,cfg['wpasswd']+'\n')
  1133. args = ['-d',cfg['tmpdir'],'-p1']
  1134. if seed_len: args += ['-l',str(seed_len)]
  1135. t = MMGenExpect(name,'mmgen-walletgen', args + [usr_rand_arg])
  1136. t.license()
  1137. t.usr_rand(usr_rand_chars)
  1138. t.passphrase_new('new MMGen wallet',cfg['wpasswd'])
  1139. t.label()
  1140. global have_dfl_wallet
  1141. if not have_dfl_wallet:
  1142. t.expect('move it to the data directory? (Y/n): ',('n','y')[gen_dfl_wallet])
  1143. if gen_dfl_wallet: have_dfl_wallet = True
  1144. t.written_to_file('MMGen wallet')
  1145. t.ok()
  1146. def walletgen_dfl_wallet(self,name,seed_len=None):
  1147. self.walletgen(name,seed_len=seed_len,gen_dfl_wallet=True)
  1148. def brainwalletgen_ref(self,name):
  1149. sl_arg = '-l%s' % cfg['seed_len']
  1150. hp_arg = '-p%s' % ref_wallet_hash_preset
  1151. label = "test.py ref. wallet (pw '%s', seed len %s)" \
  1152. % (ref_wallet_brainpass,cfg['seed_len'])
  1153. bf = 'ref.mmbrain'
  1154. args = ['-d',cfg['tmpdir'],hp_arg,sl_arg,'-ib','-L',label]
  1155. write_to_tmpfile(cfg,bf,ref_wallet_brainpass)
  1156. write_to_tmpfile(cfg,pwfile,cfg['wpasswd'])
  1157. t = MMGenExpect(name,'mmgen-walletconv', args + [usr_rand_arg])
  1158. t.license()
  1159. t.expect('Enter brainwallet: ', ref_wallet_brainpass+'\n')
  1160. t.passphrase_new('new MMGen wallet',cfg['wpasswd'])
  1161. t.usr_rand(usr_rand_chars)
  1162. sid = os.path.basename(t.written_to_file('MMGen wallet').split('-')[0])
  1163. refcheck('Seed ID',sid,cfg['seed_id'])
  1164. def refwalletgen(self,name): self.brainwalletgen_ref(name)
  1165. def passchg(self,name,wf,pf):
  1166. silence()
  1167. write_to_tmpfile(cfg,pwfile,get_data_from_file(pf))
  1168. end_silence()
  1169. t = MMGenExpect(name,'mmgen-passchg', [usr_rand_arg] +
  1170. ['-d',cfg['tmpdir'],'-p','2','-L','Changed label'] + ([],[wf])[bool(wf)])
  1171. t.license()
  1172. t.passphrase('MMGen wallet',cfgs['1']['wpasswd'],pwtype='old')
  1173. t.expect_getend('Hash preset changed to ')
  1174. t.passphrase('MMGen wallet',cfg['wpasswd'],pwtype='new') # reuse passphrase?
  1175. t.expect('Repeat passphrase: ',cfg['wpasswd']+'\n')
  1176. t.usr_rand(usr_rand_chars)
  1177. # t.expect('Enter a wallet label.*: ','Changed Label\n',regex=True)
  1178. t.expect_getend('Label changed to ')
  1179. # t.expect_getend('Key ID changed: ')
  1180. if not wf:
  1181. t.expect("Type uppercase 'YES' to confirm: ",'YES\n')
  1182. t.written_to_file('New wallet')
  1183. t.expect('Securely deleting old wallet')
  1184. # t.expect('Okay to WIPE 1 regular file ? (Yes/No)','Yes\n')
  1185. t.expect('Wallet passphrase has changed')
  1186. t.expect_getend('has been changed to ')
  1187. else:
  1188. t.written_to_file('MMGen wallet')
  1189. t.ok()
  1190. def passchg_dfl_wallet(self,name,pf):
  1191. return self.passchg(name=name,wf=None,pf=pf)
  1192. def walletchk(self,name,wf,pf,desc='MMGen wallet',add_args=[],sid=None,pw=False,extra_desc=''):
  1193. args = []
  1194. hp = cfg['hash_preset'] if 'hash_preset' in cfg else '1'
  1195. wf_arg = ([],[wf])[bool(wf)]
  1196. t = MMGenExpect(name,'mmgen-walletchk',
  1197. add_args+args+['-p',hp]+wf_arg,
  1198. extra_desc=extra_desc)
  1199. if desc != 'hidden incognito data':
  1200. t.expect("Getting %s from file '" % (desc))
  1201. if pw:
  1202. t.passphrase(desc,cfg['wpasswd'])
  1203. t.expect(
  1204. ['Passphrase is OK', 'Passphrase.* are correct'],
  1205. regex=True
  1206. )
  1207. chk = t.expect_getend('Valid %s for Seed ID ' % desc)[:8]
  1208. if sid: t.cmp_or_die(chk,sid)
  1209. else: t.ok()
  1210. def walletchk_newpass(self,name,wf,pf):
  1211. return self.walletchk(name,wf,pf,pw=True)
  1212. def walletchk_newpass_dfl_wallet(self,name,pf):
  1213. return self.walletchk_newpass(name,wf=None,pf=pf)
  1214. def delete_dfl_wallet(self,name,pf):
  1215. with open(os.path.join(cfg['tmpdir'],'del_dw_run'),'w') as f: pass
  1216. if opt.no_dw_delete: return True
  1217. for wf in [f for f in os.listdir(g.data_dir) if f[-6:]=='.mmdat']:
  1218. os.unlink(os.path.join(g.data_dir,wf))
  1219. MMGenExpect(name,'',msg_only=True)
  1220. global have_dfl_wallet
  1221. have_dfl_wallet = False
  1222. ok()
  1223. def addrgen(self,name,wf,pf=None,check_ref=False,ftype='addr',id_str=None,extra_args=[],mmtype=None):
  1224. if cfg['segwit'] and ftype[:4] != 'pass' and not mmtype: mmtype = 'segwit'
  1225. cmd_pfx = (ftype,'pass')[ftype[:4]=='pass']
  1226. t = MMGenExpect(name,'mmgen-{}gen'.format(cmd_pfx),
  1227. ['-d',cfg['tmpdir']] +
  1228. extra_args +
  1229. ([],['--type='+str(mmtype)])[bool(mmtype)] +
  1230. ([],[wf])[bool(wf)] +
  1231. ([],[id_str])[bool(id_str)] +
  1232. [cfg['{}_idx_list'.format(cmd_pfx)]],extra_desc=('','(segwit)')[mmtype=='segwit'])
  1233. t.license()
  1234. t.passphrase('MMGen wallet',cfg['wpasswd'])
  1235. t.expect('Passphrase is OK')
  1236. desc = ('address','password')[ftype[:4]=='pass']
  1237. chk = t.expect_getend(r'Checksum for {} data .*?: '.format(desc),regex=True)
  1238. if check_ref:
  1239. k = 'passfile32_chk' if ftype == 'pass32' \
  1240. else 'passfile_chk' if ftype == 'pass' \
  1241. else '{}file{}_chk'.format(ftype,'_'+mmtype if mmtype else '')
  1242. chk_ref = cfg[k] if ftype[:4] == 'pass' else cfg[k][fork][g.testnet]
  1243. refcheck('address data checksum',chk,chk_ref)
  1244. return
  1245. t.written_to_file('Addresses',oo=True)
  1246. t.ok()
  1247. def addrgen_dfl_wallet(self,name,pf=None,check_ref=False):
  1248. return self.addrgen(name,wf=None,pf=pf,check_ref=check_ref)
  1249. def refaddrgen(self,name,wf,pf):
  1250. self.addrgen(name,wf,pf=pf,check_ref=True)
  1251. def refaddrgen_compressed(self,name,wf,pf):
  1252. if opt.segwit:
  1253. msg('Skipping non-Segwit address generation'); return True
  1254. self.addrgen(name,wf,pf=pf,check_ref=True,mmtype='compressed')
  1255. def addrimport(self,name,addrfile):
  1256. outfile = os.path.join(cfg['tmpdir'],'addrfile_w_comments')
  1257. add_comments_to_addr_file(addrfile,outfile)
  1258. t = MMGenExpect(name,'mmgen-addrimport', [outfile])
  1259. t.expect_getend(r'Checksum for address data .*\[.*\]: ',regex=True)
  1260. t.expect("Type uppercase 'YES' to confirm: ",'\n')
  1261. vmsg('This is a simulation, so no addresses were actually imported into the tracking\nwallet')
  1262. t.ok(exit_val=1)
  1263. def txcreate_common(self,name,sources=['1'],non_mmgen_input='',do_label=False,txdo_args=[],add_args=[]):
  1264. if opt.verbose or opt.exact_output:
  1265. sys.stderr.write(green('Generating fake tracking wallet info\n'))
  1266. silence()
  1267. ad,tx_data = create_tx_data(sources)
  1268. dfake = create_fake_unspent_data(ad,tx_data,non_mmgen_input)
  1269. write_fake_data_to_file(repr(dfake))
  1270. cmd_args = make_txcreate_cmdline(tx_data)
  1271. end_silence()
  1272. if opt.verbose or opt.exact_output: sys.stderr.write('\n')
  1273. t = MMGenExpect(name,
  1274. 'mmgen-'+('txcreate','txdo')[bool(txdo_args)],
  1275. ([],['--rbf'])[g.proto.cap('rbf')] +
  1276. ['-f',tx_fee] + add_args + cmd_args + txdo_args)
  1277. t.license()
  1278. if txdo_args and add_args: # txdo4
  1279. t.hash_preset('key-address data','1')
  1280. t.passphrase('key-address data',cfgs['14']['kapasswd'])
  1281. t.expect('Check key-to-address validity? (y/N): ','y')
  1282. for num in tx_data:
  1283. t.expect_getend('Getting address data from file ')
  1284. chk=t.expect_getend(r'Checksum for address data .*?: ',regex=True)
  1285. verify_checksum_or_exit(tx_data[num]['chk'],chk)
  1286. # not in tracking wallet warning, (1 + num sources) times
  1287. if t.expect(['Continue anyway? (y/N): ',
  1288. 'Unable to connect to {}'.format(g.proto.daemon_name)]) == 0:
  1289. t.send('y')
  1290. else:
  1291. errmsg(red('Error: unable to connect to {}. Exiting'.format(g.proto.daemon_name)))
  1292. sys.exit(1)
  1293. for num in tx_data:
  1294. t.expect('Continue anyway? (y/N): ','y')
  1295. t.expect(r"'q'=quit view, .*?:.",'M', regex=True)
  1296. t.expect(r"'q'=quit view, .*?:.",'q', regex=True)
  1297. outputs_list = [(addrs_per_wallet+1)*i + 1 for i in range(len(tx_data))]
  1298. if non_mmgen_input: outputs_list.append(len(tx_data)*(addrs_per_wallet+1) + 1)
  1299. t.expect('outputs to spend: ',' '.join([str(i) for i in outputs_list])+'\n')
  1300. if non_mmgen_input and not txdo_args: t.expect('Accept? (y/N): ','y')
  1301. t.expect('OK? (Y/n): ','y') # fee OK?
  1302. t.expect('OK? (Y/n): ','y') # change OK?
  1303. if do_label:
  1304. t.expect('Add a comment to transaction? (y/N): ','y')
  1305. t.expect('Comment: ',ref_tx_label.encode('utf8')+'\n')
  1306. else:
  1307. t.expect('Add a comment to transaction? (y/N): ','\n')
  1308. t.tx_view()
  1309. if txdo_args: return t
  1310. t.expect('Save transaction? (y/N): ','y')
  1311. t.written_to_file('Transaction')
  1312. t.ok()
  1313. def txcreate(self,name,addrfile):
  1314. self.txcreate_common(name,sources=['1'])
  1315. def txbump(self,name,txfile,prepend_args=[],seed_args=[]):
  1316. if not g.proto.cap('rbf'):
  1317. msg('Skipping RBF'); return True
  1318. args = prepend_args + ['-q','-d',cfg['tmpdir'],txfile] + seed_args
  1319. t = MMGenExpect(name,'mmgen-txbump',args)
  1320. if seed_args:
  1321. t.hash_preset('key-address data','1')
  1322. t.passphrase('key-address data',cfgs['14']['kapasswd'])
  1323. t.expect('Check key-to-address validity? (y/N): ','y')
  1324. t.expect('deduct the fee from (Hit ENTER for the change output): ','1\n')
  1325. # Fee must be > tx_fee + network relay fee (currently 0.00001)
  1326. t.expect('OK? (Y/n): ','\n')
  1327. t.expect('Enter transaction fee: ',txbump_fee+'\n')
  1328. t.expect('OK? (Y/n): ','\n')
  1329. if seed_args: # sign and send
  1330. t.expect('Edit transaction comment? (y/N): ','\n')
  1331. for cnum,desc in (('1','incognito data'),('3','MMGen wallet'),('4','MMGen wallet')):
  1332. t.passphrase(('%s' % desc),cfgs[cnum]['wpasswd'])
  1333. t.expect("Type uppercase 'YES' to confirm: ",'YES\n')
  1334. else:
  1335. t.expect('Add a comment to transaction? (y/N): ','\n')
  1336. t.expect('Save transaction? (y/N): ','y')
  1337. t.written_to_file('Transaction')
  1338. os.unlink(txfile) # our tx file replaces the original
  1339. os.system('touch ' + os.path.join(cfg['tmpdir'],'txbump'))
  1340. t.ok()
  1341. def txdo(self,name,addrfile,wallet):
  1342. t = self.txcreate_common(name,sources=['1'],txdo_args=[wallet])
  1343. self.txsign(name,'','',pf='',save=True,has_label=False,txdo_handle=t)
  1344. self.txsend(name,'',txdo_handle=t)
  1345. def txcreate_dfl_wallet(self,name,addrfile):
  1346. self.txcreate_common(name,sources=['15'])
  1347. def txsign_end(self,t,tnum=None,has_label=False):
  1348. t.expect('Signing transaction')
  1349. cprompt = ('Add a comment to transaction','Edit transaction comment')[has_label]
  1350. t.expect('%s? (y/N): ' % cprompt,'\n')
  1351. t.expect('Save signed transaction.*?\? \(Y/n\): ','y',regex=True)
  1352. add = ' #' + tnum if tnum else ''
  1353. t.written_to_file('Signed transaction' + add, oo=True)
  1354. def txsign(self,name,txfile,wf,pf='',bumpf='',save=True,has_label=False,txdo_handle=None,extra_opts=[]):
  1355. if txdo_handle:
  1356. t = txdo_handle
  1357. else:
  1358. t = MMGenExpect(name,'mmgen-txsign', extra_opts + ['-d',cfg['tmpdir'],txfile]+([],[wf])[bool(wf)])
  1359. t.license()
  1360. t.tx_view()
  1361. t.passphrase('MMGen wallet',cfg['wpasswd'])
  1362. if txdo_handle: return
  1363. if save:
  1364. self.txsign_end(t,has_label=has_label)
  1365. t.ok()
  1366. else:
  1367. cprompt = ('Add a comment to transaction','Edit transaction comment')[has_label]
  1368. t.expect('%s? (y/N): ' % cprompt,'\n')
  1369. t.expect('Save signed transaction? (Y/n): ','n')
  1370. t.ok(exit_val=1)
  1371. def txsign_dfl_wallet(self,name,txfile,pf='',save=True,has_label=False):
  1372. return self.txsign(name,txfile,wf=None,pf=pf,save=save,has_label=has_label)
  1373. def txsend(self,name,sigfile,txdo_handle=None,really_send=False,extra_opts=[]):
  1374. if txdo_handle:
  1375. t = txdo_handle
  1376. else:
  1377. if really_send: os.environ['MMGEN_BOGUS_SEND'] = ''
  1378. t = MMGenExpect(name,'mmgen-txsend', extra_opts + ['-d',cfg['tmpdir'],sigfile])
  1379. if really_send: os.environ['MMGEN_BOGUS_SEND'] = '1'
  1380. t.license()
  1381. t.tx_view()
  1382. t.expect('Add a comment to transaction? (y/N): ','\n')
  1383. t.expect('Are you sure you want to broadcast this')
  1384. m = 'YES, I REALLY WANT TO DO THIS'
  1385. t.expect("'%s' to confirm: " % m,m+'\n')
  1386. if really_send:
  1387. txid = t.expect_getend('Transaction sent: ')
  1388. assert len(txid) == 64
  1389. else:
  1390. t.expect('BOGUS transaction NOT sent')
  1391. t.written_to_file('Sent transaction')
  1392. t.ok()
  1393. def walletconv_export(self,name,wf,desc,uargs=[],out_fmt='w',pf=None,out_pw=False):
  1394. opts = ['-d',cfg['tmpdir'],'-o',out_fmt] + uargs + \
  1395. ([],[wf])[bool(wf)] + ([],['-P',pf])[bool(pf)]
  1396. t = MMGenExpect(name,'mmgen-walletconv',opts)
  1397. t.license()
  1398. if not pf:
  1399. t.passphrase('MMGen wallet',cfg['wpasswd'])
  1400. if out_pw:
  1401. t.passphrase_new('new '+desc,cfg['wpasswd'])
  1402. t.usr_rand(usr_rand_chars)
  1403. if ' '.join(desc.split()[-2:]) == 'incognito data':
  1404. t.expect('Generating encryption key from OS random data ')
  1405. t.expect('Generating encryption key from OS random data ')
  1406. ic_id = t.expect_getend('New Incog Wallet ID: ')
  1407. t.expect('Generating encryption key from OS random data ')
  1408. if desc == 'hidden incognito data':
  1409. write_to_tmpfile(cfg,incog_id_fn,ic_id)
  1410. ret = t.expect(['Create? (Y/n): ',"'YES' to confirm: "])
  1411. if ret == 0:
  1412. t.send('\n')
  1413. t.expect('Enter file size: ',str(hincog_bytes)+'\n')
  1414. else:
  1415. t.send('YES\n')
  1416. if out_fmt == 'w': t.label()
  1417. return t.written_to_file(capfirst(desc),oo=True),t
  1418. def export_seed(self,name,wf,desc='seed data',out_fmt='seed',pf=None):
  1419. f,t = self.walletconv_export(name,wf,desc=desc,out_fmt=out_fmt,pf=pf)
  1420. silence()
  1421. msg('%s: %s' % (capfirst(desc),cyan(get_data_from_file(f,desc))))
  1422. end_silence()
  1423. t.ok()
  1424. def export_hex(self,name,wf,desc='hexadecimal seed data',out_fmt='hex',pf=None):
  1425. self.export_seed(name,wf,desc=desc,out_fmt=out_fmt,pf=pf)
  1426. def export_seed_dfl_wallet(self,name,pf,desc='seed data',out_fmt='seed'):
  1427. self.export_seed(name,wf=None,desc=desc,out_fmt=out_fmt,pf=pf)
  1428. def export_mnemonic(self,name,wf):
  1429. self.export_seed(name,wf,desc='mnemonic data',out_fmt='words')
  1430. def export_incog(self,name,wf,desc='incognito data',out_fmt='i',add_args=[]):
  1431. uargs = ['-p1',usr_rand_arg] + add_args
  1432. f,t = self.walletconv_export(name,wf,desc=desc,out_fmt=out_fmt,uargs=uargs,out_pw=True)
  1433. t.ok()
  1434. def export_incog_hex(self,name,wf):
  1435. self.export_incog(name,wf,desc='hex incognito data',out_fmt='xi')
  1436. # TODO: make outdir and hidden incog compatible (ignore --outdir and warn user?)
  1437. def export_incog_hidden(self,name,wf):
  1438. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  1439. add_args = ['-J','%s,%s'%(rf,hincog_offset)]
  1440. self.export_incog(
  1441. name,wf,desc='hidden incognito data',out_fmt='hi',add_args=add_args)
  1442. def addrgen_seed(self,name,wf,foo,desc='seed data',in_fmt='seed'):
  1443. stdout = (False,True)[desc=='seed data'] #capture output to screen once
  1444. add_args = ([],['-S'])[bool(stdout)] + get_segwit_arg(cfg)
  1445. t = MMGenExpect(name,'mmgen-addrgen', add_args +
  1446. ['-i'+in_fmt,'-d',cfg['tmpdir'],wf,cfg['addr_idx_list']])
  1447. t.license()
  1448. t.expect_getend('Valid %s for Seed ID ' % desc)
  1449. vmsg('Comparing generated checksum with checksum from previous address file')
  1450. chk = t.expect_getend(r'Checksum for address data .*?: ',regex=True)
  1451. if stdout: t.read()
  1452. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  1453. if in_fmt == 'seed':
  1454. t.ok()
  1455. else:
  1456. t.no_overwrite()
  1457. t.ok(exit_val=1)
  1458. def addrgen_hex(self,name,wf,foo,desc='hexadecimal seed data',in_fmt='hex'):
  1459. self.addrgen_seed(name,wf,foo,desc=desc,in_fmt=in_fmt)
  1460. def addrgen_mnemonic(self,name,wf,foo):
  1461. self.addrgen_seed(name,wf,foo,desc='mnemonic data',in_fmt='words')
  1462. def addrgen_incog(self,name,wf=[],foo='',in_fmt='i',desc='incognito data',args=[]):
  1463. t = MMGenExpect(name,'mmgen-addrgen', args + get_segwit_arg(cfg) + ['-i'+in_fmt,'-d',cfg['tmpdir']]+
  1464. ([],[wf])[bool(wf)] + [cfg['addr_idx_list']])
  1465. t.license()
  1466. t.expect_getend('Incog Wallet ID: ')
  1467. t.hash_preset(desc,'1')
  1468. t.passphrase('%s \w{8}' % desc, cfg['wpasswd'])
  1469. vmsg('Comparing generated checksum with checksum from address file')
  1470. chk = t.expect_getend(r'Checksum for address data .*?: ',regex=True)
  1471. verify_checksum_or_exit(get_addrfile_checksum(),chk)
  1472. t.no_overwrite()
  1473. t.ok(exit_val=1)
  1474. def addrgen_incog_hex(self,name,wf,foo):
  1475. self.addrgen_incog(name,wf,'',in_fmt='xi',desc='hex incognito data')
  1476. def addrgen_incog_hidden(self,name,wf,foo):
  1477. rf = os.path.join(cfg['tmpdir'],hincog_fn)
  1478. self.addrgen_incog(name,[],'',in_fmt='hi',desc='hidden incognito data',
  1479. args=['-H','%s,%s'%(rf,hincog_offset),'-l',str(hincog_seedlen)])
  1480. def keyaddrgen(self,name,wf,pf=None,check_ref=False,mmtype=None):
  1481. if cfg['segwit'] and not mmtype: mmtype = 'segwit'
  1482. args = ['-d',cfg['tmpdir'],usr_rand_arg,wf,cfg['addr_idx_list']]
  1483. t = MMGenExpect(name,'mmgen-keygen',
  1484. ([],['--type='+str(mmtype)])[bool(mmtype)] + args,extra_desc=('','(segwit)')[mmtype=='segwit'])
  1485. t.license()
  1486. t.passphrase('MMGen wallet',cfg['wpasswd'])
  1487. chk = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True)
  1488. if check_ref:
  1489. k = 'keyaddrfile{}_chk'.format('_'+mmtype if mmtype else '')
  1490. refcheck('key-address data checksum',chk,cfg[k][fork][g.testnet])
  1491. return
  1492. t.expect('Encrypt key list? (y/N): ','y')
  1493. t.usr_rand(usr_rand_chars)
  1494. t.hash_preset('new key list','1')
  1495. # t.passphrase_new('new key list','kafile password')
  1496. t.passphrase_new('new key list',cfg['kapasswd'])
  1497. t.written_to_file('Encrypted secret keys',oo=True)
  1498. t.ok()
  1499. def refkeyaddrgen(self,name,wf,pf):
  1500. self.keyaddrgen(name,wf,pf,check_ref=True)
  1501. def refkeyaddrgen_compressed(self,name,wf,pf):
  1502. if opt.segwit:
  1503. msg('Skipping non-Segwit key-address generation'); return True
  1504. self.keyaddrgen(name,wf,pf,check_ref=True,mmtype='compressed')
  1505. def refpasswdgen(self,name,wf,pf):
  1506. self.addrgen(name,wf,pf,check_ref=True,ftype='pass',id_str='alice@crypto.org')
  1507. def ref_b32passwdgen(self,name,wf,pf):
  1508. ea = ['--base32','--passwd-len','17']
  1509. self.addrgen(name,wf,pf,check_ref=True,ftype='pass32',id_str='фубар@crypto.org',extra_args=ea)
  1510. def txsign_keyaddr(self,name,keyaddr_file,txfile):
  1511. t = MMGenExpect(name,'mmgen-txsign', ['-d',cfg['tmpdir'],'-M',keyaddr_file,txfile])
  1512. t.license()
  1513. t.hash_preset('key-address data','1')
  1514. t.passphrase('key-address data',cfg['kapasswd'])
  1515. t.expect('Check key-to-address validity? (y/N): ','y')
  1516. t.tx_view()
  1517. self.txsign_end(t)
  1518. t.ok()
  1519. def walletgen2(self,name,del_dw_run='dummy'):
  1520. self.walletgen(name,seed_len=128)
  1521. def addrgen2(self,name,wf):
  1522. self.addrgen(name,wf,pf='')
  1523. def txcreate2(self,name,addrfile):
  1524. self.txcreate_common(name,sources=['2'])
  1525. def txsign2(self,name,txf1,wf1,txf2,wf2):
  1526. t = MMGenExpect(name,'mmgen-txsign', ['-d',cfg['tmpdir'],txf1,wf1,txf2,wf2])
  1527. t.license()
  1528. for cnum in ('1','2'):
  1529. t.tx_view()
  1530. t.passphrase('MMGen wallet',cfgs[cnum]['wpasswd'])
  1531. self.txsign_end(t,cnum)
  1532. t.ok()
  1533. def export_mnemonic2(self,name,wf):
  1534. self.export_mnemonic(name,wf)
  1535. def walletgen3(self,name,del_dw_run='dummy'):
  1536. self.walletgen(name)
  1537. def addrgen3(self,name,wf):
  1538. self.addrgen(name,wf,pf='')
  1539. def txcreate3(self,name,addrfile1,addrfile2):
  1540. self.txcreate_common(name,sources=['1','3'])
  1541. def txsign3(self,name,wf1,wf2,txf2):
  1542. t = MMGenExpect(name,'mmgen-txsign', ['-d',cfg['tmpdir'],wf1,wf2,txf2])
  1543. t.license()
  1544. t.tx_view()
  1545. for cnum in ('1','3'):
  1546. # t.expect_getend('Getting MMGen wallet data from file ')
  1547. t.passphrase('MMGen wallet',cfgs[cnum]['wpasswd'])
  1548. self.txsign_end(t)
  1549. t.ok()
  1550. def walletgen4(self,name,del_dw_run='dummy'):
  1551. bwf = os.path.join(cfg['tmpdir'],cfg['bw_filename'])
  1552. make_brainwallet_file(bwf)
  1553. seed_len = str(cfg['seed_len'])
  1554. args = ['-d',cfg['tmpdir'],'-p1',usr_rand_arg,'-l'+seed_len,'-ib']
  1555. t = MMGenExpect(name,'mmgen-walletconv', args + [bwf])
  1556. t.license()
  1557. t.passphrase_new('new MMGen wallet',cfg['wpasswd'])
  1558. t.usr_rand(usr_rand_chars)
  1559. t.label()
  1560. t.written_to_file('MMGen wallet')
  1561. t.ok()
  1562. def addrgen4(self,name,wf):
  1563. self.addrgen(name,wf,pf='')
  1564. def txcreate4(self,name,f1,f2,f3,f4,f5,f6):
  1565. self.txcreate_common(name,sources=['1','2','3','4','14'],non_mmgen_input='4',do_label=1)
  1566. def txdo4(self,name,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12):
  1567. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  1568. add_args = ['-d',cfg['tmpdir'],'-i','brain','-b'+cfg['bw_params'],'-p1','-k',non_mm_fn,'-M',f12]
  1569. t = self.txcreate_common(name,sources=['1','2','3','4','14'],non_mmgen_input='4',do_label=1,txdo_args=[f7,f8,f9,f10],add_args=add_args)
  1570. os.system('rm -f %s/*.sigtx' % cfg['tmpdir'])
  1571. self.txsign4(name,f7,f8,f9,f10,f11,f12,txdo_handle=t)
  1572. self.txsend(name,'',txdo_handle=t)
  1573. os.system('touch ' + os.path.join(cfg['tmpdir'],'txdo'))
  1574. def txbump4(self,name,f1,f2,f3,f4,f5,f6,f7,f8,f9): # f7:txfile,f9:'txdo'
  1575. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  1576. self.txbump(name,f7,prepend_args=['-p1','-k',non_mm_fn,'-M',f1],seed_args=[f2,f3,f4,f5,f6,f8])
  1577. def txsign4(self,name,f1,f2,f3,f4,f5,f6,txdo_handle=None):
  1578. if txdo_handle:
  1579. t = txdo_handle
  1580. else:
  1581. non_mm_fn = os.path.join(cfg['tmpdir'],non_mmgen_fn)
  1582. a = ['-d',cfg['tmpdir'],'-i','brain','-b'+cfg['bw_params'],'-p1','-k',non_mm_fn,'-M',f6,f1,f2,f3,f4,f5]
  1583. t = MMGenExpect(name,'mmgen-txsign',a)
  1584. t.license()
  1585. t.hash_preset('key-address data','1')
  1586. t.passphrase('key-address data',cfgs['14']['kapasswd'])
  1587. t.expect('Check key-to-address validity? (y/N): ','y')
  1588. t.tx_view()
  1589. for cnum,desc in (('1','incognito data'),('3','MMGen wallet')):
  1590. t.passphrase(('%s' % desc),cfgs[cnum]['wpasswd'])
  1591. if txdo_handle: return
  1592. self.txsign_end(t,has_label=True)
  1593. t.ok()
  1594. def tool_encrypt(self,name,infile=''):
  1595. if infile:
  1596. infn = infile
  1597. else:
  1598. d = os.urandom(1033)
  1599. tmp_fn = cfg['tool_enc_infn']
  1600. write_to_tmpfile(cfg,tmp_fn,d,binary=True)
  1601. infn = get_tmpfile_fn(cfg,tmp_fn)
  1602. t = MMGenExpect(name,'mmgen-tool',['-d',cfg['tmpdir'],usr_rand_arg,'encrypt',infn])
  1603. t.usr_rand(usr_rand_chars)
  1604. t.hash_preset('user data','1')
  1605. t.passphrase_new('user data',tool_enc_passwd)
  1606. t.written_to_file('Encrypted data')
  1607. t.ok()
  1608. # Generate the reference mmenc file
  1609. # def tool_encrypt_ref(self,name):
  1610. # infn = get_tmpfile_fn(cfg,cfg['tool_enc_ref_infn'])
  1611. # write_data_to_file(infn,cfg['tool_enc_reftext'],silent=True)
  1612. # self.tool_encrypt(name,infn)
  1613. def tool_decrypt(self,name,f1,f2):
  1614. of = name + '.out'
  1615. pre = []
  1616. t = MMGenExpect(name,'mmgen-tool',
  1617. pre+['-d',cfg['tmpdir'],'decrypt',f2,'outfile='+of,'hash_preset=1'])
  1618. t.passphrase('user data',tool_enc_passwd)
  1619. t.written_to_file('Decrypted data')
  1620. d1 = read_from_file(f1,binary=True)
  1621. d2 = read_from_file(get_tmpfile_fn(cfg,of),binary=True)
  1622. cmp_or_die(d1,d2,skip_ok=False)
  1623. def tool_find_incog_data(self,name,f1,f2):
  1624. i_id = read_from_file(f2).rstrip()
  1625. vmsg('Incog ID: %s' % cyan(i_id))
  1626. t = MMGenExpect(name,'mmgen-tool',
  1627. ['-d',cfg['tmpdir'],'find_incog_data',f1,i_id])
  1628. o = t.expect_getend('Incog data for ID %s found at offset ' % i_id)
  1629. os.unlink(f1)
  1630. cmp_or_die(hincog_offset,int(o))
  1631. # Miscellaneous tests
  1632. def autosign(self,name): # tests everything except device detection, mount/unmount
  1633. if g.platform == 'win':
  1634. msg('Skipping {} (not supported)'.format(name)); return
  1635. fdata = (('btc',''),('bch',''),('ltc','litecoin'))
  1636. tfns = [cfgs['8']['ref_tx_file'][c].format('') for c,d in fdata]
  1637. tfs = [os.path.join(ref_dir,d[1],fn) for d,fn in zip(fdata,tfns)]
  1638. try: os.mkdir(os.path.join(cfg['tmpdir'],'tx'))
  1639. except: pass
  1640. for f,fn in zip(tfs,tfns):
  1641. shutil.copyfile(f,os.path.join(cfg['tmpdir'],'tx',fn))
  1642. # make a bad tx file
  1643. with open(os.path.join(cfg['tmpdir'],'tx','bad.rawtx'),'w') as f:
  1644. f.write('bad tx data')
  1645. ls = os.listdir(cfg['tmpdir'])
  1646. opts = ['--mountpoint='+cfg['tmpdir'],'--coins=btc,bch,ltc']
  1647. # opts += ['--quiet']
  1648. mn_fn = os.path.join(ref_dir,cfgs['8']['seed_id']+'.mmwords')
  1649. mn = read_from_file(mn_fn).strip().split()
  1650. t = MMGenExpect(name,'mmgen-autosign',opts+['gen_key'],extra_desc='(gen_key)')
  1651. t.expect_getend('Wrote key file ')
  1652. t.ok()
  1653. t = MMGenExpect(name,'mmgen-autosign',opts+['setup'],extra_desc='(setup)')
  1654. t.expect('words: ','3')
  1655. t.expect('OK? (Y/n): ','\n')
  1656. for i in range(24):
  1657. t.expect('word #{}: '.format(i+1),mn[i]+'\n')
  1658. wf = t.written_to_file('Autosign wallet')
  1659. t.ok()
  1660. t = MMGenExpect(name,'mmgen-autosign',opts+['wait'],extra_desc='(sign)')
  1661. t.expect('3 transactions signed')
  1662. t.expect('1 transaction failed to sign')
  1663. t.expect('Waiting.')
  1664. t.kill(2)
  1665. t.ok(exit_val=1)
  1666. # Saved reference file tests
  1667. def ref_wallet_conv(self,name):
  1668. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1669. self.walletconv_in(name,wf,'MMGen wallet',pw=True,oo=True)
  1670. def ref_mn_conv(self,name,ext='mmwords',desc='Mnemonic data'):
  1671. wf = os.path.join(ref_dir,cfg['seed_id']+'.'+ext)
  1672. self.walletconv_in(name,wf,desc,oo=True)
  1673. def ref_seed_conv(self,name):
  1674. self.ref_mn_conv(name,ext='mmseed',desc='Seed data')
  1675. def ref_hex_conv(self,name):
  1676. self.ref_mn_conv(name,ext='mmhex',desc='Hexadecimal seed data')
  1677. def ref_brain_conv(self,name):
  1678. uopts = ['-i','b','-p','1','-l',str(cfg['seed_len'])]
  1679. self.walletconv_in(name,None,'brainwallet',uopts,oo=True)
  1680. def ref_incog_conv(self,name,wfk='ic_wallet',in_fmt='i',desc='incognito data'):
  1681. uopts = ['-i',in_fmt,'-p','1','-l',str(cfg['seed_len'])]
  1682. wf = os.path.join(ref_dir,cfg[wfk])
  1683. self.walletconv_in(name,wf,desc,uopts,oo=True,pw=True)
  1684. def ref_incox_conv(self,name):
  1685. self.ref_incog_conv(name,in_fmt='xi',wfk='ic_wallet_hex',desc='hex incognito data')
  1686. def ref_hincog_conv(self,name,wfk='hic_wallet',add_uopts=[]):
  1687. ic_f = os.path.join(ref_dir,cfg[wfk])
  1688. uopts = ['-i','hi','-p','1','-l',str(cfg['seed_len'])] + add_uopts
  1689. hi_opt = ['-H','%s,%s' % (ic_f,ref_wallet_incog_offset)]
  1690. self.walletconv_in(name,None,'hidden incognito data',uopts+hi_opt,oo=True,pw=True)
  1691. def ref_hincog_conv_old(self,name):
  1692. self.ref_hincog_conv(name,wfk='hic_wallet_old',add_uopts=['-O'])
  1693. def ref_wallet_conv_out(self,name):
  1694. self.walletconv_out(name,'MMGen wallet','w',pw=True)
  1695. def ref_mn_conv_out(self,name):
  1696. self.walletconv_out(name,'mnemonic data','mn')
  1697. def ref_seed_conv_out(self,name):
  1698. self.walletconv_out(name,'seed data','seed')
  1699. def ref_hex_conv_out(self,name):
  1700. self.walletconv_out(name,'hexadecimal seed data','hexseed')
  1701. def ref_incog_conv_out(self,name):
  1702. self.walletconv_out(name,'incognito data',out_fmt='i',pw=True)
  1703. def ref_incox_conv_out(self,name):
  1704. self.walletconv_out(name,'hex incognito data',out_fmt='xi',pw=True)
  1705. def ref_hincog_conv_out(self,name,extra_uopts=[]):
  1706. ic_f = os.path.join(cfg['tmpdir'],hincog_fn)
  1707. hi_parms = '%s,%s' % (ic_f,ref_wallet_incog_offset)
  1708. sl_parm = '-l' + str(cfg['seed_len'])
  1709. self.walletconv_out(name,
  1710. 'hidden incognito data', 'hi',
  1711. uopts=['-J',hi_parms,sl_parm] + extra_uopts,
  1712. uopts_chk=['-H',hi_parms,sl_parm],
  1713. pw=True
  1714. )
  1715. def ref_wallet_chk(self,name):
  1716. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1717. self.walletchk(name,wf,pf=None,pw=True,sid=cfg['seed_id'])
  1718. def ref_ss_chk(self,name,ss=None):
  1719. wf = os.path.join(ref_dir,'%s.%s' % (cfg['seed_id'],ss.ext))
  1720. self.walletchk(name,wf,pf=None,desc=ss.desc,sid=cfg['seed_id'])
  1721. def ref_seed_chk(self,name):
  1722. from mmgen.seed import SeedFile
  1723. self.ref_ss_chk(name,ss=SeedFile)
  1724. def ref_hex_chk(self,name):
  1725. from mmgen.seed import HexSeedFile
  1726. self.ref_ss_chk(name,ss=HexSeedFile)
  1727. def ref_mn_chk(self,name):
  1728. from mmgen.seed import Mnemonic
  1729. self.ref_ss_chk(name,ss=Mnemonic)
  1730. def ref_brain_chk(self,name,bw_file=ref_bw_file):
  1731. wf = os.path.join(ref_dir,bw_file)
  1732. add_args = ['-l%s' % cfg['seed_len'], '-p'+ref_bw_hash_preset]
  1733. self.walletchk(name,wf,pf=None,add_args=add_args,
  1734. desc='brainwallet',sid=cfg['ref_bw_seed_id'])
  1735. def ref_brain_chk_spc3(self,name):
  1736. self.ref_brain_chk(name,bw_file=ref_bw_file_spc)
  1737. def ref_hincog_chk(self,name,desc='hidden incognito data'):
  1738. for wtype,edesc,of_arg in ('hic_wallet','',[]), \
  1739. ('hic_wallet_old','(old format)',['-O']):
  1740. ic_arg = ['-H%s,%s' % (
  1741. os.path.join(ref_dir,cfg[wtype]),
  1742. ref_wallet_incog_offset
  1743. )]
  1744. slarg = ['-l%s ' % cfg['seed_len']]
  1745. hparg = ['-p1']
  1746. if wtype == 'hic_wallet_old' and opt.profile: msg('')
  1747. t = MMGenExpect(name,'mmgen-walletchk',
  1748. slarg + hparg + of_arg + ic_arg,
  1749. extra_desc=edesc)
  1750. t.passphrase(desc,cfg['wpasswd'])
  1751. if wtype == 'hic_wallet_old':
  1752. t.expect('Is the Seed ID correct? (Y/n): ','\n')
  1753. chk = t.expect_getend('Seed ID: ')
  1754. t.close()
  1755. cmp_or_die(cfg['seed_id'],chk)
  1756. def ref_addrfile_chk(self,name,ftype='addr'):
  1757. af_key = 'ref_{}file'.format(ftype)
  1758. af = os.path.join(ref_dir,(ref_subdir,'')[ftype=='passwd'],cfg[af_key])
  1759. t = MMGenExpect(name,'mmgen-tool',[ftype.replace('segwit','')+'file_chksum',af])
  1760. if ftype == 'keyaddr':
  1761. w = 'key-address data'
  1762. t.hash_preset(w,ref_kafile_hash_preset)
  1763. t.passphrase(w,ref_kafile_pass)
  1764. t.expect('Check key-to-address validity? (y/N): ','y')
  1765. o = t.read().strip().split('\n')[-1]
  1766. rc = cfg['ref_'+ftype+'file_chksum']
  1767. ref_chksum = rc if ftype == 'passwd' else rc[g.proto.base_coin.lower()][g.testnet]
  1768. cmp_or_die(ref_chksum,o)
  1769. def ref_keyaddrfile_chk(self,name):
  1770. self.ref_addrfile_chk(name,ftype='keyaddr')
  1771. def ref_passwdfile_chk(self,name):
  1772. self.ref_addrfile_chk(name,ftype='passwd')
  1773. def ref_segwitaddrfile_chk(self,name):
  1774. if not 'S' in g.proto.mmtypes:
  1775. msg_r('Skipping {} (not supported)'.format(name))
  1776. ok()
  1777. else:
  1778. self.ref_addrfile_chk(name,ftype='segwitaddr')
  1779. # def txcreate8(self,name,addrfile):
  1780. # self.txcreate_common(name,sources=['8'])
  1781. def ref_tx_chk(self,name):
  1782. tf = os.path.join(ref_dir,ref_subdir,cfg['ref_tx_file'][g.coin.lower()].format(tn_ext))
  1783. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  1784. write_to_tmpfile(cfg,pwfile,cfg['wpasswd'])
  1785. pf = get_tmpfile_fn(cfg,pwfile)
  1786. self.txsign(name,tf,wf,pf,save=False,has_label=True)
  1787. def ref_tool_decrypt(self,name):
  1788. f = os.path.join(ref_dir,ref_enc_fn)
  1789. t = MMGenExpect(name,'mmgen-tool', ['-q','decrypt',f,'outfile=-','hash_preset=1'])
  1790. t.passphrase('user data',tool_enc_passwd)
  1791. # t.expect("Type uppercase 'YES' to confirm: ",'YES\n') # comment out with popen_spawn
  1792. t.expect(NL,nonl=True)
  1793. import re
  1794. o = re.sub('\r\n','\n',t.read())
  1795. cmp_or_die(sample_text,o)
  1796. # wallet conversion tests
  1797. def walletconv_in(self,name,infile,desc,uopts=[],pw=False,oo=False):
  1798. opts = ['-d',cfg['tmpdir'],'-o','words',usr_rand_arg]
  1799. if_arg = [infile] if infile else []
  1800. d = '(convert)'
  1801. t = MMGenExpect(name,'mmgen-walletconv',opts+uopts+if_arg,extra_desc=d)
  1802. t.license()
  1803. if desc == 'brainwallet':
  1804. t.expect('Enter brainwallet: ',ref_wallet_brainpass+'\n')
  1805. if pw:
  1806. t.passphrase(desc,cfg['wpasswd'])
  1807. if name[:19] == 'ref_hincog_conv_old':
  1808. t.expect('Is the Seed ID correct? (Y/n): ','\n')
  1809. else:
  1810. t.expect(['Passphrase is OK',' are correct'])
  1811. # Output
  1812. wf = t.written_to_file('Mnemonic data',oo=oo)
  1813. t.close()
  1814. t.ok()
  1815. # back check of result
  1816. if opt.profile: msg('')
  1817. self.walletchk(name,wf,pf=None,
  1818. desc='mnemonic data',
  1819. sid=cfg['seed_id'],
  1820. extra_desc='(check)'
  1821. )
  1822. def walletconv_out(self,name,desc,out_fmt='w',uopts=[],uopts_chk=[],pw=False):
  1823. opts = ['-d',cfg['tmpdir'],'-p1','-o',out_fmt] + uopts
  1824. infile = os.path.join(ref_dir,cfg['seed_id']+'.mmwords')
  1825. t = MMGenExpect(name,'mmgen-walletconv',[usr_rand_arg]+opts+[infile],extra_desc='(convert)')
  1826. add_args = ['-l%s' % cfg['seed_len']]
  1827. t.license()
  1828. if pw:
  1829. t.passphrase_new('new '+desc,cfg['wpasswd'])
  1830. t.usr_rand(usr_rand_chars)
  1831. if ' '.join(desc.split()[-2:]) == 'incognito data':
  1832. for i in (1,2,3):
  1833. t.expect('Generating encryption key from OS random data ')
  1834. if desc == 'hidden incognito data':
  1835. ret = t.expect(['Create? (Y/n): ',"'YES' to confirm: "])
  1836. if ret == 0:
  1837. t.send('\n')
  1838. t.expect('Enter file size: ',str(hincog_bytes)+'\n')
  1839. else:
  1840. t.send('YES\n')
  1841. if out_fmt == 'w': t.label()
  1842. wf = t.written_to_file(capfirst(desc),oo=True)
  1843. pf = None
  1844. t.ok()
  1845. if desc == 'hidden incognito data':
  1846. add_args += uopts_chk
  1847. wf = None
  1848. if opt.profile: msg('')
  1849. self.walletchk(name,wf,pf=pf,
  1850. desc=desc,sid=cfg['seed_id'],pw=pw,
  1851. add_args=add_args,
  1852. extra_desc='(check)')
  1853. def regtest_setup(self,name):
  1854. if g.testnet:
  1855. die(2,'--testnet option incompatible with regtest test suite')
  1856. try: shutil.rmtree(os.path.join(data_dir,'regtest'))
  1857. except: pass
  1858. os.environ['MMGEN_TEST_SUITE'] = '' # mnemonic is piped to stdin, so stop being a terminal
  1859. t = MMGenExpect(name,'mmgen-regtest',['-n','setup'])
  1860. os.environ['MMGEN_TEST_SUITE'] = '1'
  1861. for s in 'Starting setup','Creating','Mined','Creating','Creating','Setup complete':
  1862. t.expect(s)
  1863. t.ok()
  1864. def regtest_walletgen(self,name,user):
  1865. t = MMGenExpect(name,'mmgen-walletgen',['-q','-r0','-p1','--'+user])
  1866. t.passphrase_new('new MMGen wallet','abc')
  1867. t.label()
  1868. t.expect('move it to the data directory? (Y/n): ','y')
  1869. t.written_to_file('MMGen wallet')
  1870. t.ok()
  1871. def regtest_walletgen_bob(self,name): return self.regtest_walletgen(name,'bob')
  1872. def regtest_walletgen_alice(self,name): return self.regtest_walletgen(name,'alice')
  1873. @staticmethod
  1874. def regtest_user_dir(user,coin=None):
  1875. return os.path.join(data_dir,'regtest',coin or g.coin.lower(),user)
  1876. def regtest_user_sid(self,user):
  1877. return os.path.basename(get_file_with_ext('mmdat',self.regtest_user_dir(user)))[:8]
  1878. def regtest_addrgen(self,name,user,wf=None,passwd='abc',addr_range='1-5'):
  1879. from mmgen.addr import MMGenAddrType
  1880. for mmtype in g.proto.mmtypes:
  1881. t = MMGenExpect(name,'mmgen-addrgen',
  1882. ['--quiet','--'+user,'--type='+mmtype,'--outdir={}'.format(self.regtest_user_dir(user))] +
  1883. ([],[wf])[bool(wf)] + [addr_range],
  1884. extra_desc='({})'.format(MMGenAddrType.mmtypes[mmtype]['name']))
  1885. t.passphrase('MMGen wallet',passwd)
  1886. t.written_to_file('Addresses')
  1887. t.ok()
  1888. def regtest_addrgen_bob(self,name): self.regtest_addrgen(name,'bob')
  1889. def regtest_addrgen_alice(self,name): self.regtest_addrgen(name,'alice')
  1890. def regtest_addrimport(self,name,user,sid=None,addr_range='1-5',num_addrs=5):
  1891. id_strs = { 'legacy':'', 'compressed':'-C', 'segwit':'-S' }
  1892. if not sid: sid = self.regtest_user_sid(user)
  1893. from mmgen.addr import MMGenAddrType
  1894. for mmtype in g.proto.mmtypes:
  1895. desc = MMGenAddrType.mmtypes[mmtype]['name']
  1896. fn = os.path.join(self.regtest_user_dir(user),
  1897. '{}{}{}[{}].addrs'.format(sid,altcoin_pfx,id_strs[desc],addr_range))
  1898. t = MMGenExpect(name,'mmgen-addrimport', ['--quiet','--'+user,'--batch',fn],extra_desc='('+desc+')')
  1899. t.expect('Importing')
  1900. t.expect('{} addresses imported'.format(num_addrs))
  1901. t.ok()
  1902. def regtest_addrimport_bob(self,name): self.regtest_addrimport(name,'bob')
  1903. def regtest_addrimport_alice(self,name): self.regtest_addrimport(name,'alice')
  1904. def regtest_fund_wallet(self,name,user,mmtype,amt,sid=None,addr_range='1-5'):
  1905. if not sid: sid = self.regtest_user_sid(user)
  1906. addr = self.get_addr_from_regtest_addrlist(user,sid,mmtype,0,addr_range=addr_range)
  1907. t = MMGenExpect(name,'mmgen-regtest', ['send',str(addr),str(amt)])
  1908. t.expect('Sending {} {}'.format(amt,g.coin))
  1909. t.expect('Mined 1 block')
  1910. t.ok()
  1911. def regtest_fund_bob(self,name): self.regtest_fund_wallet(name,'bob','C',rtFundAmt)
  1912. def regtest_fund_alice(self,name): self.regtest_fund_wallet(name,'alice',('L','S')[g.proto.cap('segwit')],rtFundAmt)
  1913. def regtest_user_bal(self,name,user,bal):
  1914. t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses','showempty=1'])
  1915. total = t.expect_getend('TOTAL: ')
  1916. cmp_or_die(total,'{} {}'.format(bal,g.coin))
  1917. def regtest_alice_bal1(self,name):
  1918. return self.regtest_user_bal(name,'alice',rtFundAmt)
  1919. def regtest_bob_bal1(self,name):
  1920. return self.regtest_user_bal(name,'bob',rtFundAmt)
  1921. def regtest_bob_bal2(self,name):
  1922. return self.regtest_user_bal(name,'bob',rtBals[0])
  1923. def regtest_bob_bal3(self,name):
  1924. return self.regtest_user_bal(name,'bob',rtBals[1])
  1925. def regtest_bob_bal4(self,name):
  1926. return self.regtest_user_bal(name,'bob',rtBals[2])
  1927. def regtest_bob_bal5(self,name):
  1928. return self.regtest_user_bal(name,'bob',rtBals[3])
  1929. def regtest_bob_alice_bal(self,name):
  1930. t = MMGenExpect(name,'mmgen-regtest',['get_balances'])
  1931. t.expect('Switching')
  1932. ret = t.expect_getend("Bob's balance:").strip()
  1933. cmp_or_die(ret,rtBals[4],skip_ok=True)
  1934. ret = t.expect_getend("Alice's balance:").strip()
  1935. cmp_or_die(ret,rtBals[5],skip_ok=True)
  1936. ret = t.expect_getend("Total balance:").strip()
  1937. cmp_or_die(ret,rtBals[6],skip_ok=True)
  1938. t.ok()
  1939. def regtest_user_txdo( self,name,user,fee,
  1940. outputs_cl,
  1941. outputs_prompt,
  1942. extra_args=[],
  1943. wf=None,
  1944. pw='abc',
  1945. no_send=False,
  1946. do_label=False,
  1947. bad_locktime=False):
  1948. os.environ['MMGEN_BOGUS_SEND'] = ''
  1949. t = MMGenExpect(name,'mmgen-txdo',
  1950. ['-d',cfg['tmpdir'],'-B','--'+user,'--tx-fee='+fee]
  1951. + extra_args + ([],[wf])[bool(wf)] + outputs_cl)
  1952. os.environ['MMGEN_BOGUS_SEND'] = '1'
  1953. t.expect(r"'q'=quit view, .*?:.",'M',regex=True) # sort by mmid
  1954. t.expect(r"'q'=quit view, .*?:.",'q',regex=True)
  1955. t.expect('outputs to spend: ',outputs_prompt+'\n')
  1956. t.expect('OK? (Y/n): ','y') # fee OK?
  1957. t.expect('OK? (Y/n): ','y') # change OK?
  1958. if do_label:
  1959. t.expect('Add a comment to transaction? (y/N): ','y')
  1960. t.expect('Comment: ',ref_tx_label.encode('utf8')+'\n')
  1961. t.expect('View decoded transaction\? .*?: ','n',regex=True)
  1962. else:
  1963. t.expect('Add a comment to transaction? (y/N): ','\n')
  1964. t.expect('View decoded transaction\? .*?: ','t',regex=True)
  1965. t.expect('to continue: ','\n')
  1966. t.passphrase('MMGen wallet',pw)
  1967. t.written_to_file('Signed transaction')
  1968. if no_send:
  1969. t.read()
  1970. exit_val = 0
  1971. else:
  1972. t.expect('to confirm: ','YES, I REALLY WANT TO DO THIS\n')
  1973. s,exit_val = (('Transaction sent',0),("can't be included",1))[bad_locktime]
  1974. t.expect(s)
  1975. t.ok(exit_val)
  1976. def regtest_bob_split1(self,name):
  1977. sid = self.regtest_user_sid('bob')
  1978. outputs_cl = [sid+':C:1,100', sid+':L:2,200',sid+':'+rtBobOp3]
  1979. return self.regtest_user_txdo(name,'bob',rtFee[0],outputs_cl,'1',do_label=True)
  1980. def get_addr_from_regtest_addrlist(self,user,sid,mmtype,idx,addr_range='1-5'):
  1981. id_str = { 'L':'', 'S':'-S', 'C':'-C' }[mmtype]
  1982. ext = '{}{}{}[{}].addrs'.format(sid,altcoin_pfx,id_str,addr_range)
  1983. fn = get_file_with_ext(ext,self.regtest_user_dir(user),no_dot=True)
  1984. silence()
  1985. psave = g.proto
  1986. g.proto = CoinProtocol(g.coin,True)
  1987. addr = AddrList(fn).data[idx].addr
  1988. g.proto = psave
  1989. end_silence()
  1990. return addr
  1991. def create_tx_outputs(self,user,data):
  1992. sid = self.regtest_user_sid(user)
  1993. return [self.get_addr_from_regtest_addrlist(user,sid,mmtype,idx-1)+amt_str for mmtype,idx,amt_str in data]
  1994. def regtest_bob_rbf_send(self,name):
  1995. outputs_cl = self.create_tx_outputs('alice',(('L',1,',60'),('C',1,',40'))) # alice_sid:L:1, alice_sid:C:1
  1996. outputs_cl += [self.regtest_user_sid('bob')+':'+rtBobOp3]
  1997. return self.regtest_user_txdo(name,'bob',rtFee[1],outputs_cl,'3',
  1998. extra_args=([],['--rbf'])[g.proto.cap('rbf')])
  1999. def regtest_bob_send_non_mmgen(self,name):
  2000. outputs_cl = self.create_tx_outputs('alice',(
  2001. (('L','S')[g.proto.cap('segwit')],2,',10'),
  2002. (('L','S')[g.proto.cap('segwit')],3,'')
  2003. )) # alice_sid:S:2, alice_sid:S:3
  2004. fn = os.path.join(cfg['tmpdir'],'non-mmgen.keys')
  2005. return self.regtest_user_txdo(name,'bob',rtFee[3],outputs_cl,'3-9',extra_args=['--keys-from-file='+fn])
  2006. def regtest_user_txbump(self,name,user,txfile,fee,red_op,no_send=False):
  2007. if not g.proto.cap('rbf'):
  2008. msg('Skipping RBF'); return True
  2009. os.environ['MMGEN_BOGUS_SEND'] = ''
  2010. t = MMGenExpect(name,'mmgen-txbump',
  2011. ['-d',cfg['tmpdir'],'--send','--'+user,'--tx-fee='+fee,'--output-to-reduce='+red_op] + [txfile])
  2012. os.environ['MMGEN_BOGUS_SEND'] = '1'
  2013. t.expect('OK? (Y/n): ','y') # output OK?
  2014. t.expect('OK? (Y/n): ','y') # fee OK?
  2015. t.expect('Add a comment to transaction? (y/N): ','n')
  2016. t.passphrase('MMGen wallet','abc')
  2017. t.written_to_file('Signed transaction')
  2018. if not no_send:
  2019. t.expect('to confirm: ','YES, I REALLY WANT TO DO THIS\n')
  2020. t.expect('Transaction sent')
  2021. t.written_to_file('Signed transaction')
  2022. t.read()
  2023. t.ok()
  2024. def regtest_bob_rbf_bump(self,name):
  2025. txfile = get_file_with_ext(',{}].sigtx'.format(rtFee[1][:-1]),cfg['tmpdir'],delete=False,no_dot=True)
  2026. return self.regtest_user_txbump(name,'bob',txfile,rtFee[2],'c')
  2027. def regtest_generate(self,name,coin=None,num_blocks=1):
  2028. int(num_blocks)
  2029. if coin: opt.coin = coin
  2030. t = MMGenExpect(name,'mmgen-regtest',['generate',str(num_blocks)])
  2031. t.expect('Mined {} block'.format(num_blocks))
  2032. t.ok()
  2033. def regtest_get_mempool(self,name):
  2034. t = MMGenExpect(name,'mmgen-regtest',['show_mempool'])
  2035. return eval(t.read())
  2036. def regtest_get_mempool1(self,name):
  2037. mp = self.regtest_get_mempool(name)
  2038. if len(mp) != 1:
  2039. rdie(2,'Mempool has more or less than one TX!')
  2040. write_to_tmpfile(cfg,'rbf_txid',mp[0]+'\n')
  2041. ok()
  2042. def regtest_get_mempool2(self,name):
  2043. if not g.proto.cap('rbf'):
  2044. msg('Skipping post-RBF mempool check'); return True
  2045. mp = self.regtest_get_mempool(name)
  2046. if len(mp) != 1:
  2047. rdie(2,'Mempool has more or less than one TX!')
  2048. chk = read_from_tmpfile(cfg,'rbf_txid')
  2049. if chk.strip() == mp[0]:
  2050. rdie(2,'TX in mempool has not changed! RBF bump failed')
  2051. ok()
  2052. @staticmethod
  2053. def gen_pairs(n):
  2054. return [subprocess.check_output(
  2055. ['python',os.path.join('cmds','mmgen-tool'),'--testnet=1','-r0','randpair','compressed={}'.format((i+1)%2)]).split()
  2056. for i in range(n)]
  2057. def regtest_bob_pre_import(self,name):
  2058. pairs = self.gen_pairs(5)
  2059. write_to_tmpfile(cfg,'non-mmgen.keys','\n'.join([a[0] for a in pairs])+'\n')
  2060. write_to_tmpfile(cfg,'non-mmgen.addrs','\n'.join([a[1] for a in pairs])+'\n')
  2061. return self.regtest_user_txdo(name,'bob',rtFee[4],[pairs[0][1]],'3')
  2062. def regtest_user_import(self,name,user,args):
  2063. t = MMGenExpect(name,'mmgen-addrimport',['--quiet','--'+user]+args)
  2064. t.expect('Importing')
  2065. t.expect('OK')
  2066. t.ok()
  2067. def regtest_bob_import_addr(self,name):
  2068. addr = read_from_tmpfile(cfg,'non-mmgen.addrs').split()[0]
  2069. return self.regtest_user_import(name,'bob',['--rescan','--address='+addr])
  2070. def regtest_bob_import_list(self,name):
  2071. fn = os.path.join(cfg['tmpdir'],'non-mmgen.addrs')
  2072. return self.regtest_user_import(name,'bob',['--addrlist',fn])
  2073. def regtest_bob_split2(self,name):
  2074. addrs = read_from_tmpfile(cfg,'non-mmgen.addrs').split()
  2075. amts = (a for a in (1.12345678,2.87654321,3.33443344,4.00990099,5.43214321))
  2076. outputs1 = ['{},{}'.format(a,amts.next()) for a in addrs]
  2077. sid = self.regtest_user_sid('bob')
  2078. outputs2 = [sid+':C:2,6', sid+':L:3,7',sid+(':L:1',':S:3')[g.proto.cap('segwit')]]
  2079. return self.regtest_user_txdo(name,'bob',rtFee[5],outputs1+outputs2,'1-2')
  2080. def regtest_user_add_label(self,name,user,addr,label):
  2081. t = MMGenExpect(name,'mmgen-tool',['--'+user,'add_label',addr,label])
  2082. t.expect('Added label.*in tracking wallet',regex=True)
  2083. t.ok()
  2084. def regtest_user_remove_label(self,name,user,addr):
  2085. t = MMGenExpect(name,'mmgen-tool',['--'+user,'remove_label',addr])
  2086. t.expect('Removed label.*in tracking wallet',regex=True)
  2087. t.ok()
  2088. def regtest_alice_add_label1(self,name):
  2089. sid = self.regtest_user_sid('alice')
  2090. return self.regtest_user_add_label(name,'alice',sid+':C:1','Original Label')
  2091. def regtest_alice_add_label2(self,name):
  2092. sid = self.regtest_user_sid('alice')
  2093. return self.regtest_user_add_label(name,'alice',sid+':C:1','Replacement Label')
  2094. def regtest_alice_remove_label1(self,name):
  2095. sid = self.regtest_user_sid('alice')
  2096. return self.regtest_user_remove_label(name,'alice',sid+':C:1')
  2097. def regtest_user_chk_label(self,name,user,addr,label):
  2098. t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses','all_labels=1'])
  2099. t.expect('{}\s+\S{{30}}\S+\s+{}\s+'.format(addr,label),regex=True)
  2100. t.ok()
  2101. def regtest_alice_chk_label1(self,name):
  2102. sid = self.regtest_user_sid('alice')
  2103. return self.regtest_user_chk_label(name,'alice',sid+':C:1','Original Label')
  2104. def regtest_alice_chk_label2(self,name):
  2105. sid = self.regtest_user_sid('alice')
  2106. return self.regtest_user_chk_label(name,'alice',sid+':C:1','Replacement Label')
  2107. def regtest_alice_chk_label3(self,name):
  2108. sid = self.regtest_user_sid('alice')
  2109. return self.regtest_user_chk_label(name,'alice',sid+':C:1','Edited Label')
  2110. def regtest_alice_chk_label4(self,name):
  2111. sid = self.regtest_user_sid('alice')
  2112. return self.regtest_user_chk_label(name,'alice',sid+':C:1','-')
  2113. def regtest_user_edit_label(self,name,user,output,label):
  2114. t = MMGenExpect(name,'mmgen-txcreate',['-B','--'+user,'-i'])
  2115. t.expect(r"'q'=quit view, .*?:.",'M',regex=True)
  2116. t.expect(r"'q'=quit view, .*?:.",'l',regex=True)
  2117. t.expect(r"Enter unspent.*return to main menu\):.",output+'\n',regex=True)
  2118. t.expect(r"Enter label text.*return to main menu\):.",label+'\n',regex=True)
  2119. t.expect(r"'q'=quit view, .*?:.",'q',regex=True)
  2120. t.ok()
  2121. def regtest_alice_edit_label1(self,name):
  2122. return self.regtest_user_edit_label(name,'alice','1','Edited Label')
  2123. def regtest_stop(self,name):
  2124. t = MMGenExpect(name,'mmgen-regtest',['stop'])
  2125. t.ok()
  2126. def regtest_split_setup(self,name):
  2127. if g.coin != 'BTC': die(1,'Test valid only for coin BTC')
  2128. opt.coin = 'BTC'
  2129. return self.regtest_setup(name)
  2130. def regtest_split_fork(self,name):
  2131. opt.coin = 'B2X'
  2132. t = MMGenExpect(name,'mmgen-regtest',['fork','btc'])
  2133. t.expect('Creating fork from coin')
  2134. t.expect('successfully created')
  2135. t.ok()
  2136. def regtest_split_start(self,name,coin):
  2137. opt.coin = coin
  2138. t = MMGenExpect(name,'mmgen-regtest',['bob'])
  2139. t.expect('Starting')
  2140. t.expect('done')
  2141. t.ok()
  2142. def regtest_split_start_btc(self,name): self.regtest_split_start(name,coin='BTC')
  2143. def regtest_split_start_b2x(self,name): self.regtest_split_start(name,coin='B2X')
  2144. def regtest_split_gen_btc(self,name): self.regtest_generate(name,coin='BTC')
  2145. def regtest_split_gen_b2x(self,name): self.regtest_generate(name,coin='B2X',num_blocks=100)
  2146. def regtest_split_gen_b2x2(self,name): self.regtest_generate(name,coin='B2X')
  2147. def regtest_split_do_split(self,name):
  2148. opt.coin = 'B2X'
  2149. sid = self.regtest_user_sid('bob')
  2150. t = MMGenExpect(name,'mmgen-split',[
  2151. '--bob',
  2152. '--outdir='+cfg['tmpdir'],
  2153. '--tx-fees=0.0001,0.0003',
  2154. sid+':S:1',sid+':S:2'])
  2155. t.expect(r"'q'=quit view, .*?:.",'q', regex=True)
  2156. t.expect('outputs to spend: ','1\n')
  2157. for tx in ('timelocked','split'):
  2158. for q in ('fee','change'): t.expect('OK? (Y/n): ','y')
  2159. t.expect('Add a comment to transaction? (y/N): ','n')
  2160. t.expect('View decoded transaction\? .*?: ','t',regex=True)
  2161. t.expect('to continue: ','\n')
  2162. t.written_to_file('Long chain (timelocked) transaction')
  2163. t.written_to_file('Short chain transaction')
  2164. t.ok()
  2165. def regtest_split_sign(self,name,coin,ext):
  2166. wf = get_file_with_ext('mmdat',self.regtest_user_dir('bob',coin=coin.lower()))
  2167. txfile = get_file_with_ext(ext,cfg['tmpdir'],no_dot=True)
  2168. opt.coin = coin
  2169. self.txsign(name,txfile,wf,extra_opts=['--bob'])
  2170. def regtest_split_sign_b2x(self,name):
  2171. return self.regtest_split_sign(name,coin='B2X',ext='533].rawtx')
  2172. def regtest_split_sign_btc(self,name):
  2173. return self.regtest_split_sign(name,coin='BTC',ext='9997].rawtx')
  2174. def regtest_split_send(self,name,coin,ext):
  2175. opt.coin = coin
  2176. txfile = get_file_with_ext(ext,cfg['tmpdir'],no_dot=True)
  2177. self.txsend(name,txfile,really_send=True,extra_opts=['--bob'])
  2178. def regtest_split_send_b2x(self,name):
  2179. return self.regtest_split_send(name,coin='B2X',ext='533].sigtx')
  2180. def regtest_split_send_btc(self,name):
  2181. return self.regtest_split_send(name,coin='BTC',ext='9997].sigtx')
  2182. def regtest_split_txdo_timelock(self,name,coin,locktime,bad_locktime):
  2183. opt.coin = coin
  2184. sid = self.regtest_user_sid('bob')
  2185. self.regtest_user_txdo(
  2186. name,'bob','0.0001',[sid+':S:5'],'1',pw='abc',
  2187. extra_args=['--locktime='+str(locktime)],
  2188. bad_locktime=bad_locktime)
  2189. def regtest_split_txdo_timelock_bad_btc(self,name):
  2190. self.regtest_split_txdo_timelock(name,'BTC',locktime=8888,bad_locktime=True)
  2191. def regtest_split_txdo_timelock_good_btc(self,name):
  2192. self.regtest_split_txdo_timelock(name,'BTC',locktime=1321009871,bad_locktime=False)
  2193. def regtest_split_txdo_timelock_bad_b2x(self,name):
  2194. self.regtest_split_txdo_timelock(name,'B2X',locktime=8888,bad_locktime=True)
  2195. def regtest_split_txdo_timelock_good_b2x(self,name):
  2196. self.regtest_split_txdo_timelock(name,'B2X',locktime=1321009871,bad_locktime=False)
  2197. # def regtest_user_txdo(self,name,user,fee,outputs_cl,outputs_prompt,extra_args=[],wf=None,pw='abc',no_send=False,do_label=False):
  2198. # undocumented admin commands
  2199. ref_tx_setup = regtest_setup
  2200. ref_tx_generate = regtest_generate
  2201. def ref_tx_addrgen_bob_ref_wallet(self,name):
  2202. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  2203. self.regtest_addrgen(name,'bob',wf=wf,passwd=cfg['wpasswd'],addr_range='1-100')
  2204. def ref_tx_addrimport_bob_ref_wallet(self,name):
  2205. self.regtest_addrimport(name,'bob',sid=cfg['seed_id'],addr_range='1-100',num_addrs=100)
  2206. def ref_tx_fund_bob(self,name):
  2207. mmtype = g.proto.mmtypes[-1]
  2208. self.regtest_fund_wallet(name,'bob',mmtype,rtFundAmt,sid=cfg['seed_id'],addr_range='1-100')
  2209. def ref_tx_bob_split(self,name):
  2210. sid = cfg['seed_id']
  2211. outputs_cl = [sid+':C:1,100', sid+':L:2,200',sid+':'+rtBobOp3]
  2212. wf = os.path.join(ref_dir,cfg['ref_wallet'])
  2213. return self.regtest_user_txdo(name,'bob',rtFee[0],outputs_cl,'1',do_label=True,wf=wf,pw=cfg['wpasswd'])
  2214. def ref_tx_bob_create_tx(self,name):
  2215. sid = cfg['seed_id']
  2216. psave = g.proto
  2217. g.proto = CoinProtocol(g.coin,True)
  2218. privhex = PrivKey(os.urandom(32),compressed=True)
  2219. addr = AddrGenerator('p2pkh').to_addr(KeyGenerator().to_pubhex(privhex))
  2220. g.proto = psave
  2221. outputs_cl = [sid+':{}:3,1.1234'.format(g.proto.mmtypes[-1]), sid+':C:5,5.5555',sid+':L:4',addr+',100']
  2222. pw = cfg['wpasswd']
  2223. # create tx in cwd
  2224. t = MMGenExpect(name,'mmgen-txcreate',[
  2225. '-B',
  2226. '--bob',
  2227. '--tx-fee='+rtFee[0],
  2228. '--locktime=1320969600'
  2229. ] + outputs_cl)
  2230. # [os.path.join(ref_dir,cfg['ref_wallet'])])
  2231. t.expect(r"'q'=quit view, .*?:.",'M',regex=True) # sort by mmid
  2232. t.expect(r"'q'=quit view, .*?:.",'q',regex=True)
  2233. t.expect('outputs to spend: ','1 2 3\n')
  2234. t.expect('OK? (Y/n): ','y') # fee OK?
  2235. t.expect('OK? (Y/n): ','y') # change OK?
  2236. t.expect('Add a comment to transaction? (y/N): ','y')
  2237. t.expect('Comment: ',ref_tx_label.encode('utf8')+'\n')
  2238. t.expect('View decoded transaction\? .*?: ','n',regex=True)
  2239. t.expect('Save transaction? (y/N): ','y')
  2240. fn = t.written_to_file('Transaction')
  2241. write_to_tmpfile(cfg,'ref_tx_fn',fn)
  2242. t.ok()
  2243. def ref_tx_bob_modify_tx(self,name):
  2244. MMGenExpect(name,'',msg_only=True)
  2245. fn = read_from_tmpfile(cfg,'ref_tx_fn')
  2246. with open(fn) as f:
  2247. lines = f.read().splitlines()
  2248. from mmgen.obj import BTCAmt,LTCAmt,BCHAmt,B2XAmt
  2249. tx = {}
  2250. for k,i in (('in',3),('out',4)):
  2251. tx[k] = eval(lines[i])
  2252. tx[k+'_addrs'] = [i['addr'] for i in tx[k]]
  2253. psave = g.proto
  2254. g.proto = CoinProtocol(g.coin,True)
  2255. from mmgen.obj import CoinAddr
  2256. for k in ('in_addrs','out_addrs'):
  2257. tx[k+'_hex'] = [(CoinAddr(a).hex,CoinAddr(a).addr_fmt) for a in tx[k]]
  2258. g.proto = psave
  2259. for k in ('in_addrs','out_addrs'):
  2260. tx[k+'_conv'] = [g.proto.hexaddr2addr(h,(False,True)[f=='p2sh']) for h,f in tx[k+'_hex']]
  2261. for k in ('in','out'):
  2262. for i in range(len(tx[k])):
  2263. tx[k][i]['addr'] = tx[k+'_addrs_conv'][i]
  2264. lines_tn = [lines[1].replace('REGTEST','TESTNET')] + lines[2:]
  2265. o_tn = '\n'.join([make_chksum_6(' '.join(lines_tn))] + lines_tn)+'\n'
  2266. fn_tn = fn.replace('.rawtx','.testnet.rawtx')
  2267. lines_mn = [lines[1].replace('REGTEST','MAINNET'),
  2268. lines[2],
  2269. repr(tx['in']),
  2270. repr(tx['out'])] + lines[5:]
  2271. o_mn = '\n'.join([make_chksum_6(' '.join(lines_mn))] + lines_mn)+'\n'
  2272. fn_mn = fn.replace('.rawtx','.mainnet.rawtx')
  2273. ok()
  2274. write_data_to_file(fn_tn,o_tn,'testnet TX data',ask_overwrite=False)
  2275. write_data_to_file(fn_mn,o_mn,'mainnet TX data',ask_overwrite=False)
  2276. # END methods
  2277. for k in (
  2278. 'ref_wallet_conv',
  2279. 'ref_mn_conv',
  2280. 'ref_seed_conv',
  2281. 'ref_hex_conv',
  2282. 'ref_brain_conv',
  2283. 'ref_incog_conv',
  2284. 'ref_incox_conv',
  2285. 'ref_hincog_conv',
  2286. 'ref_hincog_conv_old',
  2287. 'ref_wallet_conv_out',
  2288. 'ref_mn_conv_out',
  2289. 'ref_seed_conv_out',
  2290. 'ref_hex_conv_out',
  2291. 'ref_incog_conv_out',
  2292. 'ref_incox_conv_out',
  2293. 'ref_hincog_conv_out',
  2294. 'ref_wallet_chk',
  2295. 'refwalletgen',
  2296. 'ref_seed_chk',
  2297. 'ref_hex_chk',
  2298. 'ref_mn_chk',
  2299. 'ref_brain_chk',
  2300. 'ref_hincog_chk',
  2301. 'refaddrgen',
  2302. 'refkeyaddrgen',
  2303. 'refaddrgen_compressed',
  2304. 'refkeyaddrgen_compressed',
  2305. 'refpasswdgen',
  2306. 'ref_b32passwdgen'
  2307. ):
  2308. for i in ('1','2','3'):
  2309. locals()[k+i] = locals()[k]
  2310. for k in ('walletgen','addrgen','keyaddrgen'): locals()[k+'14'] = locals()[k]
  2311. # create temporary dirs
  2312. if not opt.resume and not opt.skip_deps:
  2313. if g.platform == 'win':
  2314. for cfg in sorted(cfgs):
  2315. mk_tmpdir(cfgs[cfg]['tmpdir'])
  2316. else:
  2317. for cfg in sorted(cfgs):
  2318. src = os.path.join(shm_dir,cfgs[cfg]['tmpdir'].split('/')[-1])
  2319. mk_tmpdir(src)
  2320. try:
  2321. os.unlink(cfgs[cfg]['tmpdir'])
  2322. except OSError as e:
  2323. if e.errno != 2: raise
  2324. finally:
  2325. os.symlink(src,cfgs[cfg]['tmpdir'])
  2326. have_dfl_wallet = False
  2327. # main()
  2328. if opt.pause:
  2329. import termios,atexit
  2330. fd = sys.stdin.fileno()
  2331. old = termios.tcgetattr(fd)
  2332. def at_exit():
  2333. termios.tcsetattr(fd, termios.TCSADRAIN, old)
  2334. atexit.register(at_exit)
  2335. start_time = int(time.time())
  2336. def end_msg():
  2337. t = int(time.time()) - start_time
  2338. m = '{} test{} performed. Elapsed time: {:02d}:{:02d}\n'
  2339. sys.stderr.write(green(m.format(cmd_total,suf(cmd_total),t/60,t%60)))
  2340. ts = MMGenTestSuite()
  2341. if cmd_args and cmd_args[0] == 'admin':
  2342. cmd_args.pop(0)
  2343. cmd_data = cmd_data_admin
  2344. cmd_list = cmd_list_admin
  2345. try:
  2346. if cmd_args:
  2347. for arg in cmd_args:
  2348. if arg in utils:
  2349. globals()[arg](cmd_args[cmd_args.index(arg)+1:])
  2350. sys.exit(0)
  2351. elif 'info_'+arg in cmd_data:
  2352. dirs = cmd_data['info_'+arg][1]
  2353. if dirs: clean(dirs)
  2354. for cmd in cmd_list[arg]:
  2355. check_needs_rerun(ts,cmd,build=True)
  2356. elif arg in meta_cmds:
  2357. for cmd in meta_cmds[arg]:
  2358. check_needs_rerun(ts,cmd,build=True)
  2359. elif arg in cmd_data:
  2360. check_needs_rerun(ts,arg,build=True)
  2361. else:
  2362. die(1,'%s: unrecognized command' % arg)
  2363. else:
  2364. clean()
  2365. for cmd in cmd_data:
  2366. if cmd == 'info_regtest': break # don't run everything after this by default
  2367. if cmd[:5] == 'info_':
  2368. msg(green('%sTesting %s' % (('\n','')[bool(opt.resume)],cmd_data[cmd][0])))
  2369. continue
  2370. ts.do_cmd(cmd)
  2371. if cmd is not cmd_data.keys()[-1]: do_between()
  2372. except KeyboardInterrupt:
  2373. die(1,'\nExiting at user request')
  2374. except opt.traceback and Exception:
  2375. with open('my.err') as f:
  2376. t = f.readlines()
  2377. if t: msg_r('\n'+yellow(''.join(t[:-1]))+red(t[-1]))
  2378. die(1,blue('Test script exited with error'))
  2379. except:
  2380. sys.stderr = stderr_save
  2381. raise
  2382. end_msg()