ct_main.py 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
  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.cmdtest_py_d.ct_main: Basic operations tests for the cmdtest.py test suite
  20. """
  21. import sys,os
  22. from mmgen.util import msg,msg_r,async_run,capfirst,get_extension,die
  23. from mmgen.color import green,cyan
  24. from mmgen.fileutil import get_data_from_file,write_data_to_file
  25. from mmgen.wallet import get_wallet_cls
  26. from mmgen.wallet.mmgen import wallet as MMGenWallet
  27. from mmgen.wallet.incog import wallet as IncogWallet
  28. from mmgen.rpc import rpc_init
  29. from ..include.common import (
  30. cfg,
  31. vmsg,
  32. joinpath,
  33. silence,
  34. end_silence,
  35. getrand,
  36. getrandnum,
  37. getrandnum_range,
  38. getrandhex,
  39. strip_ansi_escapes
  40. )
  41. from .common import (
  42. pwfile,
  43. hincog_fn,
  44. get_file_with_ext,
  45. get_comment,
  46. tx_comment_lat_cyr_gr,
  47. hincog_offset,
  48. hincog_bytes,
  49. hincog_seedlen,
  50. incog_id_fn,
  51. non_mmgen_fn
  52. )
  53. from .ct_base import CmdTestBase
  54. from .ct_shared import CmdTestShared
  55. def make_brainwallet_file(fn):
  56. # Print random words with random whitespace in between
  57. wl = rwords.split()
  58. nwords,ws_list,max_spaces = 10,' \n',5
  59. def rand_ws_seq():
  60. nchars = getrandnum(1) % max_spaces + 1
  61. return ''.join([ws_list[getrandnum_range(1,200) % len(ws_list)] for i in range(nchars)])
  62. rand_pairs = [wl[getrandnum_range(1,200) % len(wl)] + rand_ws_seq() for i in range(nwords)]
  63. d = ''.join(rand_pairs).rstrip() + '\n'
  64. if cfg.verbose:
  65. msg_r(f'Brainwallet password:\n{cyan(d)}')
  66. write_data_to_file(cfg,fn,d,'brainwallet password',quiet=True,ignore_opt_outdir=True)
  67. def verify_checksum_or_exit(checksum,chk):
  68. chk = strip_ansi_escapes(chk)
  69. if checksum != chk:
  70. die( 'TestSuiteFatalException', f'Checksum error: {chk}' )
  71. vmsg(green('Checksums match: ') + cyan(chk))
  72. addrs_per_wallet = 8
  73. # 100 words chosen randomly from here:
  74. # https://github.com/bitcoin/bips/pull/432/files/6332230d63149a950d05db78964a03bfd344e6b0
  75. rwords = """
  76. алфавит алый амнезия амфора артист баян белый биатлон брат бульвар веревка вернуть весть возраст
  77. восток горло горный десяток дятел ежевика жест жизнь жрать заговор здание зона изделие итог кабина
  78. кавалер каждый канал керосин класс клятва князь кривой крыша крючок кузнец кукла ландшафт мальчик
  79. масса масштаб матрос мрак муравей мычать негодяй носок ночной нрав оборот оружие открытие оттенок
  80. палуба пароход период пехота печать письмо позор полтора понятие поцелуй почему приступ пруд пятно
  81. ранее режим речь роса рынок рябой седой сердце сквозь смех снимок сойти соперник спичка стон
  82. сувенир сугроб суть сцена театр тираж толк удивить улыбка фирма читатель эстония эстрада юность
  83. """
  84. class CmdTestMain(CmdTestBase,CmdTestShared):
  85. 'basic operations with emulated tracking wallet'
  86. tmpdir_nums = [1,2,3,4,5,14,15,16,20,21]
  87. networks = ('btc','btc_tn','ltc','ltc_tn','bch','bch_tn')
  88. passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet','rpc_backend')
  89. segwit_opts_ok = True
  90. color = True
  91. need_daemon = True
  92. cmd_group = (
  93. ('walletgen_dfl_wallet', (15,'wallet generation (default wallet)', [[[],15]])),
  94. ('subwalletgen_dfl_wallet', (15,'subwallet generation (default wallet)', [[[pwfile],15]])),
  95. ('export_seed_dfl_wallet', (15,'seed export to mmseed format (default wallet)', [[[pwfile],15]])),
  96. ('addrgen_dfl_wallet', (15,'address generation (default wallet)', [[[pwfile],15]])),
  97. ('txcreate_dfl_wallet', (15,'transaction creation (default wallet)', [[['addrs'],15]])),
  98. ('txsign_dfl_wallet', (15,'transaction signing (default wallet)', [[['rawtx',pwfile],15]])),
  99. ('passchg_dfl_wallet', (16,'password, label and hash preset change (default wallet)',[[[pwfile],15]])),
  100. ('walletchk_newpass_dfl_wallet', (16,'wallet check with new pw, label and hash preset', [[[pwfile],16]])),
  101. ('delete_dfl_wallet', (15,'delete default wallet', [[[pwfile],15]])),
  102. ('walletgen', (1,'wallet generation', [[['del_dw_run'],15]])),
  103. ('subwalletgen', (1,'subwallet generation', [[['mmdat'],1]])),
  104. ('subwalletgen_mnemonic', (1,'subwallet generation (to mnemonic format)', [[['mmdat'],1]])),
  105. # ('walletchk', (1,'wallet check', [[['mmdat'],1]])),
  106. ('passchg', (5,'password, label and hash preset change', [[['mmdat',pwfile],1]])),
  107. ('passchg_keeplabel',(5,'password, label and hash preset change (keep label)', [[['mmdat',pwfile],1]])),
  108. ('passchg_usrlabel', (
  109. 5,
  110. 'password, label and hash preset change (interactive label)',
  111. [
  112. [['mmdat',pwfile],1]
  113. ]
  114. )
  115. ),
  116. ('walletchk_newpass',(5,'wallet check with new pw, label and hash preset', [[['mmdat',pwfile],5]])),
  117. ('addrgen', (1,'address generation', [[['mmdat'],1]])),
  118. ('txcreate', (1,'transaction creation', [[['addrs'],1]])),
  119. ('txbump', (1,'transaction fee bumping (no send)', [[['rawtx'],1]])),
  120. ('txsign', (1,'transaction signing', [[['mmdat','rawtx'],1]])),
  121. ('txsend', (1,'transaction sending', [[['sigtx'],1]])),
  122. # txdo must go after txsign
  123. ('txdo', (1,'online transaction', [[['sigtx','mmdat'],1]])),
  124. ('export_seed', (1,'seed export to mmseed format', [[['mmdat'],1]])),
  125. ('export_hex', (1,'seed export to hexadecimal format', [[['mmdat'],1]])),
  126. ('export_mnemonic', (1,'seed export to mmwords format', [[['mmdat'],1]])),
  127. ('export_bip39', (1,'seed export to bip39 format', [[['mmdat'],1]])),
  128. ('export_incog', (1,'seed export to mmincog format', [[['mmdat'],1]])),
  129. ('export_incog_hex',(1,'seed export to mmincog hex format', [[['mmdat'],1]])),
  130. ('export_incog_hidden',(1,'seed export to hidden mmincog format', [[['mmdat'],1]])),
  131. ('addrgen_seed', (1,'address generation from mmseed file', [[['mmseed','addrs'],1]])),
  132. ('addrgen_hex', (1,'address generation from mmhex file', [[['mmhex','addrs'],1]])),
  133. ('addrgen_mnemonic',(1,'address generation from mmwords file', [[['mmwords','addrs'],1]])),
  134. ('addrgen_incog', (1,'address generation from mmincog file', [[['mmincog','addrs'],1]])),
  135. ('addrgen_incog_hex',(1,'address generation from mmincog hex file', [[['mmincox','addrs'],1]])),
  136. ('addrgen_incog_hidden',(1,'address generation from hidden mmincog file', [[[hincog_fn,'addrs'],1]])),
  137. ('keyaddrgen', (1,'key-address file generation', [[['mmdat'],1]])),
  138. ('txsign_keyaddr',(1,'transaction signing with key-address file', [[['akeys.mmenc','rawtx'],1]])),
  139. ('txcreate_ni', (1,'transaction creation (non-interactive)', [[['addrs'],1]])),
  140. ('walletgen2',(2,'wallet generation (2), 128-bit seed', [[['del_dw_run'],15]])),
  141. ('addrgen2', (2,'address generation (2)', [[['mmdat'],2]])),
  142. ('txcreate2', (2,'transaction creation (2)', [[['addrs'],2]])),
  143. ('txsign2', (
  144. 2,
  145. 'transaction signing, two transactions',
  146. [
  147. [['mmdat','rawtx'],1],
  148. [['mmdat','rawtx'],2]
  149. ]
  150. )
  151. ),
  152. ('export_mnemonic2', (
  153. 2,
  154. 'seed export to mmwords format (2)',
  155. [
  156. [['mmdat'],2]
  157. ]
  158. )
  159. ),
  160. ('walletgen3',(3,'wallet generation (3)', [[['del_dw_run'],15]])),
  161. ('addrgen3', (3,'address generation (3)', [[['mmdat'],3]])),
  162. ('txcreate3', (
  163. 3,
  164. 'tx creation with inputs and outputs from two wallets',
  165. [
  166. [['addrs'],1],
  167. [['addrs'],3]
  168. ]
  169. )
  170. ),
  171. ('txsign3', (
  172. 3,
  173. 'tx signing with inputs and outputs from two wallets',
  174. [
  175. [['mmdat'],1],
  176. [['mmdat','rawtx'],3]
  177. ]
  178. )
  179. ),
  180. ('walletgen14', (14,'wallet generation (14)', [[['del_dw_run'],15]],14)),
  181. ('addrgen14', (14,'address generation (14)', [[['mmdat'],14]])),
  182. ('keyaddrgen14',(14,'key-address file generation (14)', [[['mmdat'],14]],14)),
  183. ('walletgen4',(4,'wallet generation (4) (brainwallet)', [[['del_dw_run'],15]])),
  184. ('addrgen4', (4,'address generation (4)', [[['mmdat'],4]])),
  185. ('txcreate4', (
  186. 4,
  187. 'tx creation with inputs and outputs from four seed sources, key-address file '
  188. 'and non-MMGen inputs and outputs',
  189. [
  190. [['addrs'],1],
  191. [['addrs'],2],
  192. [['addrs'],3],
  193. [['addrs'],4],
  194. [['addrs','akeys.mmenc'],14]
  195. ]
  196. )
  197. ),
  198. ('txsign4', (
  199. 4,
  200. 'tx signing with inputs and outputs from incog file, mnemonic file, wallet, '
  201. 'brainwallet, key-address file and non-MMGen inputs and outputs',
  202. [
  203. [['mmincog'],1],
  204. [['mmwords'],2],
  205. [['mmdat'],3],
  206. [['mmbrain','rawtx'],4],
  207. [['akeys.mmenc'],14]
  208. ]
  209. )
  210. ),
  211. ('txdo4', (
  212. 4,
  213. 'tx creation,signing and sending with inputs and outputs from four seed sources, '
  214. 'key-address file and non-MMGen inputs and outputs',
  215. [
  216. [['addrs'],1],
  217. [['addrs'],2],
  218. [['addrs'],3],
  219. [['addrs'],4],
  220. [['addrs','akeys.mmenc'],14],
  221. [['mmincog'],1],
  222. [['mmwords'],2],
  223. [['mmdat'],3],
  224. [['mmbrain','rawtx'],4],
  225. [['akeys.mmenc'],14]
  226. ]
  227. )
  228. ), # must go after txsign4
  229. ('txbump4', (
  230. 4,
  231. 'tx fee bump + send with inputs and outputs from four seed sources, key-address file '
  232. 'and non-MMGen inputs and outputs',
  233. [
  234. [['akeys.mmenc'],14],
  235. [['mmincog'],1],
  236. [['mmwords'],2],
  237. [['mmdat'],3],
  238. [['akeys.mmenc'],14],
  239. [['mmbrain','sigtx','mmdat','txdo'],4]
  240. ]
  241. )
  242. ), # must go after txsign4
  243. ('walletgen5',(20,'wallet generation (5)', [[['del_dw_run'],15]],20)),
  244. ('addrgen5', (20,'address generation (5)', [[['mmdat'],20]])),
  245. ('txcreate5', (20,'transaction creation with bad vsize (5)', [[['addrs'],20]])),
  246. ('txsign5', (20,'transaction signing with bad vsize', [[['mmdat','rawtx'],20]])),
  247. ('walletgen6',(21,'wallet generation (6)', [[['del_dw_run'],15]],21)),
  248. ('addrgen6', (21,'address generation (6)', [[['mmdat'],21]])),
  249. ('txcreate6', (21,'transaction creation with corrected vsize (6)', [[['addrs'],21]])),
  250. ('txsign6', (21,'transaction signing with corrected vsize', [[['mmdat','rawtx'],21]])),
  251. )
  252. segwit_do = (
  253. 'walletgen',
  254. 'addrgen',
  255. 'txcreate',
  256. 'txbump',
  257. 'txsign',
  258. 'txsend',
  259. 'txdo',
  260. 'export_incog',
  261. 'keyaddrgen',
  262. 'txsign_keyaddr',
  263. 'txcreate_ni',
  264. 'walletgen2',
  265. 'addrgen2',
  266. 'txcreate2',
  267. 'txsign2',
  268. 'export_mnemonic2',
  269. 'walletgen3',
  270. 'addrgen3',
  271. 'txcreate3',
  272. 'txsign3',
  273. 'walletgen14',
  274. 'addrgen14',
  275. 'keyaddrgen14',
  276. 'walletgen4',
  277. 'addrgen4',
  278. 'txcreate4',
  279. 'txsign4',
  280. 'txdo4',
  281. 'txbump4',
  282. 'walletgen5',
  283. 'addrgen5',
  284. 'txcreate5',
  285. 'txsign5',
  286. 'walletgen6',
  287. 'addrgen6',
  288. 'txcreate6',
  289. 'txsign6',
  290. )
  291. def __init__(self,trunner,cfgs,spawn):
  292. CmdTestBase.__init__(self,trunner,cfgs,spawn)
  293. if trunner is None or self.proto.coin.lower() not in self.networks:
  294. return
  295. if self.proto.coin in ('BTC','BCH','LTC'):
  296. self.tx_fee = {'btc':'0.0001','bch':'0.001','ltc':'0.01'}[self.proto.coin.lower()]
  297. self.txbump_fee = {'btc':'123s','bch':'567s','ltc':'12345s'}[self.proto.coin.lower()]
  298. self.unspent_data_file = joinpath('test','trash','unspent.json')
  299. self.spawn_env['MMGEN_BOGUS_UNSPENT_DATA'] = self.unspent_data_file
  300. @property
  301. def lbl_id(self):
  302. if not hasattr(self,'_lbl_id'):
  303. rpc = async_run(rpc_init(cfg,self.proto))
  304. self._lbl_id = ('account','label')['label_api' in rpc.caps]
  305. return self._lbl_id
  306. def _get_addrfile_checksum(self,display=False):
  307. addrfile = self.get_file_with_ext('addrs')
  308. from mmgen.addrlist import AddrList
  309. silence()
  310. chk = AddrList( cfg, self.proto, addrfile ).chksum
  311. end_silence()
  312. if cfg.verbose and display:
  313. msg(f'Checksum: {cyan(chk)}')
  314. return chk
  315. def walletgen_dfl_wallet(self,seed_len=None):
  316. return self.walletgen(seed_len=seed_len,gen_dfl_wallet=True)
  317. def subwalletgen_dfl_wallet(self,pf):
  318. return self.subwalletgen(wf='default')
  319. def export_seed_dfl_wallet(self,pf,out_fmt='seed'):
  320. return self.export_seed(wf=None,out_fmt=out_fmt,pf=pf)
  321. def addrgen_dfl_wallet(self,pf=None,check_ref=False):
  322. return self.addrgen(wf=None,check_ref=check_ref,dfl_wallet=True)
  323. def txcreate_dfl_wallet(self,addrfile):
  324. return self.txcreate_common(sources=['15'])
  325. def txsign_dfl_wallet(self,txfile,pf='',save=True,has_label=False):
  326. return self.txsign(None,txfile,save=save,has_label=has_label,dfl_wallet=True)
  327. def passchg_dfl_wallet(self,pf):
  328. return self.passchg(wf=None,pf=pf,dfl_wallet=True)
  329. def walletchk_newpass_dfl_wallet(self,pf):
  330. return self.walletchk_newpass(wf=None,wcls=MMGenWallet,pf=pf,dfl_wallet=True)
  331. def delete_dfl_wallet(self,pf):
  332. self.write_to_tmpfile('del_dw_run',b'',binary=True)
  333. if cfg.no_dw_delete:
  334. return 'skip'
  335. for wf in [f for f in os.listdir(cfg.data_dir) if f[-6:]=='.mmdat']:
  336. os.unlink(joinpath(cfg.data_dir,wf))
  337. self.spawn('',msg_only=True)
  338. self.have_dfl_wallet = False
  339. return 'ok'
  340. def walletgen(self,del_dw_run='dummy',seed_len=None,gen_dfl_wallet=False):
  341. self.write_to_tmpfile(pwfile,self.wpasswd+'\n')
  342. args = ['-p1']
  343. if not gen_dfl_wallet:
  344. args += ['-d',self.tmpdir]
  345. if seed_len:
  346. args += ['-l',str(seed_len)]
  347. t = self.spawn('mmgen-walletgen', args + [self.usr_rand_arg])
  348. t.license()
  349. t.usr_rand(self.usr_rand_chars)
  350. wcls = MMGenWallet
  351. t.passphrase_new('new '+wcls.desc,self.wpasswd)
  352. t.label()
  353. if not self.have_dfl_wallet and gen_dfl_wallet:
  354. t.expect('move it to the data directory? (Y/n): ','y')
  355. self.have_dfl_wallet = True
  356. t.written_to_file(capfirst(wcls.desc))
  357. return t
  358. def subwalletgen(self,wf):
  359. args = [self.usr_rand_arg,'-p1','-d',self.tr.trash_dir,'-L','Label']
  360. if wf != 'default':
  361. args += [wf]
  362. t = self.spawn('mmgen-subwalletgen', args + ['10s'])
  363. t.license()
  364. wcls = MMGenWallet
  365. t.passphrase(wcls.desc,self.cfgs['1']['wpasswd'])
  366. t.expect(r'Generating subseed.*\D10S',regex=True)
  367. t.passphrase_new('new '+wcls.desc,'foo')
  368. t.usr_rand(self.usr_rand_chars)
  369. fn = t.written_to_file(capfirst(wcls.desc))
  370. ext = get_extension(fn)
  371. assert ext,f'incorrect file extension: {ext}'
  372. return t
  373. def subwalletgen_mnemonic(self,wf):
  374. icls = get_wallet_cls(ext=get_extension(wf))
  375. ocls = get_wallet_cls('words')
  376. args = [self.usr_rand_arg,'-p1','-d',self.tr.trash_dir,'-o',ocls.fmt_codes[0],wf,'3L']
  377. t = self.spawn('mmgen-subwalletgen', args)
  378. t.license()
  379. t.passphrase(icls.desc,self.cfgs['1']['wpasswd'])
  380. t.expect(r'Generating subseed.*\D3L',regex=True)
  381. fn = t.written_to_file(capfirst(ocls.desc))
  382. ext = get_extension(fn)
  383. assert ext == ocls.ext,f'incorrect file extension: {ext}'
  384. return t
  385. def passchg(self,wf,pf,label_action='cmdline',dfl_wallet=False,delete=False):
  386. silence()
  387. self.write_to_tmpfile( pwfile, get_data_from_file(cfg,pf) )
  388. end_silence()
  389. add_args = {
  390. 'cmdline': ['-d',self.tmpdir,'-L','Changed label (UTF-8) α'],
  391. 'keep': ['-d',self.tr.trash_dir,'--keep-label'],
  392. 'user': ['-d',self.tr.trash_dir]
  393. }[label_action]
  394. t = self.spawn('mmgen-passchg', add_args + [self.usr_rand_arg, '-p2'] + ([wf] if wf else []))
  395. t.license()
  396. wcls = MMGenWallet
  397. t.passphrase(wcls.desc,self.cfgs['1']['wpasswd'],pwtype='old')
  398. t.expect_getend('Hash preset changed to ')
  399. t.passphrase(wcls.desc,self.wpasswd,pwtype='new') # reuse passphrase?
  400. t.expect('Repeat new passphrase: ',self.wpasswd+'\n')
  401. t.usr_rand(self.usr_rand_chars)
  402. if label_action == 'user':
  403. t.expect('Enter a wallet label.*: ','Interactive Label (UTF-8) α\n',regex=True)
  404. t.expect_getend(('Label changed to ','Reusing label ')[label_action=='keep'])
  405. # t.expect_getend('Key ID changed: ')
  406. if dfl_wallet:
  407. t.expect("Type uppercase 'YES' to confirm: ",'YES\n')
  408. t.written_to_file('New wallet')
  409. t.expect('Securely deleting old wallet')
  410. # t.expect('Okay to WIPE 1 regular file ? (Yes/No)','Yes\n')
  411. t.expect('Wallet passphrase has changed')
  412. t.expect_getend('has been changed to ')
  413. else:
  414. t.written_to_file(capfirst(wcls.desc))
  415. t.expect( 'Securely delete .*: ', ('y' if delete else 'n' ), regex=True )
  416. if delete:
  417. t.expect( 'Securely deleting' )
  418. return t
  419. def passchg_keeplabel(self,wf,pf):
  420. return self.passchg(wf,pf,label_action='keep',delete=True)
  421. def passchg_usrlabel(self,wf,pf):
  422. return self.passchg(wf,pf,label_action='user')
  423. def walletchk_newpass(self,wf,pf,wcls=None,dfl_wallet=False):
  424. return self.walletchk(wf,wcls=wcls,dfl_wallet=dfl_wallet)
  425. def _write_fake_data_to_file(self,d):
  426. write_data_to_file(cfg,self.unspent_data_file,d,'Unspent outputs',quiet=True,ignore_opt_outdir=True)
  427. if cfg.verbose or cfg.exact_output:
  428. sys.stderr.write(f'Fake transaction wallet data written to file {self.unspent_data_file!r}\n')
  429. def _create_fake_unspent_entry(self,coinaddr,al_id=None,idx=None,comment=None,non_mmgen=False,segwit=False):
  430. if 'S' not in self.proto.mmtypes:
  431. segwit = False
  432. if comment:
  433. comment = ' ' + comment
  434. k = coinaddr.addr_fmt
  435. if not segwit and k == 'p2sh':
  436. k = 'p2pkh'
  437. s_beg,s_end = { 'p2pkh': ('76a914','88ac'),
  438. 'p2sh': ('a914','87'),
  439. 'bech32': (self.proto.witness_vernum_hex + '14','') }[k]
  440. amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[self.proto.coin.lower()]
  441. ret = {
  442. self.lbl_id: (
  443. f'{self.proto.base_coin.lower()}:{coinaddr}' if non_mmgen
  444. else f'{al_id}:{idx}{comment}' ),
  445. 'vout': int(getrandnum(4) % 8),
  446. 'txid': getrandhex(32),
  447. 'amount': self.proto.coin_amt('{}.{}'.format(
  448. amt1 + getrandnum(4) % amt2,
  449. getrandnum(4) % 100000000 )),
  450. 'address': coinaddr,
  451. 'spendable': False,
  452. 'scriptPubKey': f'{s_beg}{coinaddr.bytes.hex()}{s_end}',
  453. 'confirmations': getrandnum(3) // 20 # max: 838860 (6 digits)
  454. }
  455. return ret
  456. def _create_fake_unspent_data(self,adata,tx_data,non_mmgen_input='',non_mmgen_input_compressed=True):
  457. out = []
  458. for d in tx_data.values():
  459. al = adata.addrlist(al_id=d['al_id'])
  460. for n,(idx,coinaddr) in enumerate(al.addrpairs()):
  461. comment = get_comment(do_shuffle=not cfg.test_suite_deterministic)
  462. out.append(self._create_fake_unspent_entry(coinaddr,d['al_id'],idx,comment,segwit=d['segwit']))
  463. if n == 0: # create a duplicate address. This means addrs_per_wallet += 1
  464. out.append(self._create_fake_unspent_entry(coinaddr,d['al_id'],idx,comment,segwit=d['segwit']))
  465. if non_mmgen_input:
  466. from mmgen.key import PrivKey
  467. privkey = PrivKey(
  468. self.proto,
  469. getrand(32),
  470. compressed = non_mmgen_input_compressed,
  471. pubkey_type = 'std' )
  472. from mmgen.addrgen import KeyGenerator,AddrGenerator
  473. rand_coinaddr = AddrGenerator(
  474. cfg,
  475. self.proto,
  476. ('legacy','compressed')[non_mmgen_input_compressed]
  477. ).to_addr(KeyGenerator( cfg, self.proto, 'std' ).gen_data(privkey))
  478. of = joinpath(self.cfgs[non_mmgen_input]['tmpdir'],non_mmgen_fn)
  479. write_data_to_file(
  480. cfg = cfg,
  481. outfile = of,
  482. data = privkey.wif + '\n',
  483. desc = f'compressed {self.proto.name} key',
  484. quiet = True,
  485. ignore_opt_outdir = True )
  486. out.append(self._create_fake_unspent_entry(rand_coinaddr,non_mmgen=True,segwit=False))
  487. return out
  488. def _create_tx_data(self,sources,addrs_per_wallet=addrs_per_wallet):
  489. from mmgen.addrlist import AddrList,AddrIdxList
  490. from mmgen.addrdata import AddrData
  491. tx_data,ad = {},AddrData(self.proto)
  492. for s in sources:
  493. addrfile = get_file_with_ext(self.cfgs[s]['tmpdir'],'addrs')
  494. al = AddrList( cfg, self.proto, addrfile )
  495. ad.add(al)
  496. aix = AddrIdxList(fmt_str=self.cfgs[s]['addr_idx_list'])
  497. if len(aix) != addrs_per_wallet:
  498. die( 'TestSuiteFatalException', f'Address index list length != {addrs_per_wallet}: {repr(aix)}' )
  499. tx_data[s] = {
  500. 'addrfile': addrfile,
  501. 'chk': al.chksum,
  502. 'al_id': al.al_id,
  503. 'addr_idxs': aix[-2:],
  504. 'segwit': self.cfgs[s]['segwit']
  505. }
  506. return ad,tx_data
  507. def _make_txcreate_cmdline(self,tx_data):
  508. from mmgen.key import PrivKey
  509. privkey = PrivKey(self.proto,getrand(32),compressed=True,pubkey_type='std')
  510. t = ('compressed','segwit')['S' in self.proto.mmtypes]
  511. from mmgen.addrgen import KeyGenerator,AddrGenerator
  512. rand_coinaddr = AddrGenerator( cfg, self.proto, t ).to_addr(
  513. KeyGenerator( cfg, self.proto, 'std' ).gen_data(privkey)
  514. )
  515. # total of two outputs must be < 10 BTC (<1000 LTC)
  516. mods = {'btc':(6,4),'bch':(6,4),'ltc':(600,400)}[self.proto.coin.lower()]
  517. for k in self.cfgs:
  518. self.cfgs[k]['amts'] = [None,None]
  519. for idx,mod in enumerate(mods):
  520. self.cfgs[k]['amts'][idx] = '{}.{}'.format(
  521. getrandnum(4) % mod,
  522. str(getrandnum(4))[:5] )
  523. cmd_args = ['--outdir='+self.tmpdir]
  524. for num in tx_data:
  525. s = tx_data[num]
  526. cmd_args += [
  527. '{}:{},{}'.format(
  528. s['al_id'],
  529. s['addr_idxs'][0],
  530. self.cfgs[num]['amts'][0] )]
  531. # + one change address and one BTC address
  532. if num is list(tx_data.keys())[-1]:
  533. cmd_args += [
  534. '{}:{}'.format(
  535. s['al_id'],
  536. s['addr_idxs'][1] )]
  537. cmd_args += [
  538. '{},{}'.format(
  539. rand_coinaddr,
  540. self.cfgs[num]['amts'][1] )]
  541. return cmd_args + [tx_data[num]['addrfile'] for num in tx_data]
  542. def txcreate_common(
  543. self,
  544. sources = ['1'],
  545. non_mmgen_input = '',
  546. do_label = False,
  547. txdo_args = [],
  548. add_args = [],
  549. view = 'n',
  550. addrs_per_wallet = addrs_per_wallet,
  551. non_mmgen_input_compressed = True,
  552. cmdline_inputs = False,
  553. tweaks = []):
  554. if cfg.verbose or cfg.exact_output:
  555. sys.stderr.write(green('Generating fake tracking wallet info\n'))
  556. silence()
  557. ad,tx_data = self._create_tx_data(sources,addrs_per_wallet)
  558. dfake = self._create_fake_unspent_data(ad,tx_data,non_mmgen_input,non_mmgen_input_compressed)
  559. import json
  560. from mmgen.rpc import json_encoder
  561. self._write_fake_data_to_file(json.dumps(dfake,cls=json_encoder))
  562. cmd_args = self._make_txcreate_cmdline(tx_data)
  563. if cmdline_inputs:
  564. from mmgen.tw.shared import TwLabel
  565. cmd_args = [
  566. '--inputs={},{},{},{},{},{}'.format(
  567. TwLabel(self.proto,dfake[0][self.lbl_id]).mmid, dfake[1]['address'],
  568. TwLabel(self.proto,dfake[2][self.lbl_id]).mmid, dfake[3]['address'],
  569. TwLabel(self.proto,dfake[4][self.lbl_id]).mmid, dfake[5]['address']
  570. ),
  571. f'--outdir={self.tr.trash_dir}'
  572. ] + cmd_args[1:]
  573. end_silence()
  574. if cfg.verbose or cfg.exact_output:
  575. sys.stderr.write('\n')
  576. t = self.spawn(
  577. 'mmgen-'+('txcreate','txdo')[bool(txdo_args)],
  578. ([],['--rbf'])[self.proto.cap('rbf')] +
  579. ['-f',self.tx_fee,'-B'] + add_args + cmd_args + txdo_args)
  580. if t.expect([('Get','Unsigned transac')[cmdline_inputs],r'Unable to connect to \S+'],regex=True) == 1:
  581. die( 'TestSuiteException', '\n'+t.p.after )
  582. if cmdline_inputs:
  583. t.written_to_file('tion')
  584. return t
  585. t.license()
  586. for num in tx_data:
  587. t.expect_getend('ting address data from file ')
  588. chk=t.expect_getend(r'Checksum for address data .*?: ',regex=True)
  589. verify_checksum_or_exit(tx_data[num]['chk'],chk)
  590. # not in tracking wallet warning, (1 + num sources) times
  591. for num in range(len(tx_data) + 1):
  592. t.expect('Continue anyway? (y/N): ','y')
  593. outputs_list = [(addrs_per_wallet+1)*i + 1 for i in range(len(tx_data))]
  594. if non_mmgen_input:
  595. outputs_list.append(len(tx_data)*(addrs_per_wallet+1) + 1)
  596. self.txcreate_ui_common(t,
  597. menu = (['M'],['M','D','D','D','D','m','o'])[self.test_name=='txcreate'],
  598. inputs = ' '.join(map(str,outputs_list)),
  599. add_comment = ('',tx_comment_lat_cyr_gr)[do_label],
  600. view = view,
  601. tweaks = tweaks )
  602. if txdo_args and add_args: # txdo4
  603. t.do_decrypt_ka_data(pw=self.cfgs['14']['kapasswd'])
  604. return t
  605. def txcreate(self,addrfile):
  606. return self.txcreate_common(sources=['1'],add_args=['--vsize-adj=1.01'])
  607. def txbump(self,txfile,prepend_args=[],seed_args=[]):
  608. if not self.proto.cap('rbf'):
  609. msg('Skipping RBF')
  610. return 'skip'
  611. args = prepend_args + ['--quiet','--outdir='+self.tmpdir,txfile] + seed_args
  612. t = self.spawn('mmgen-txbump',args)
  613. if seed_args:
  614. t.do_decrypt_ka_data(pw=self.cfgs['14']['kapasswd'])
  615. t.expect('deduct the fee from (Hit ENTER for the change output): ','1\n')
  616. # Fee must be > tx_fee + network relay fee (currently 0.00001)
  617. t.expect('OK? (Y/n): ','\n')
  618. t.expect('Enter transaction fee: ',self.txbump_fee+'\n')
  619. t.expect('OK? (Y/n): ','\n')
  620. if seed_args: # sign and send
  621. t.do_comment(False,has_label=True)
  622. for cnum,wcls in (('1',IncogWallet),('3',MMGenWallet),('4',MMGenWallet)):
  623. t.passphrase(wcls.desc,self.cfgs[cnum]['wpasswd'])
  624. self._do_confirm_send(t,quiet=not cfg.debug,confirm_send=True)
  625. if cfg.debug:
  626. t.written_to_file('Transaction')
  627. else:
  628. t.do_comment(False)
  629. t.expect('Save fee-bumped transaction? (y/N): ','y')
  630. t.written_to_file('Fee-bumped transaction')
  631. os.unlink(txfile) # our tx file replaces the original
  632. cmd = 'touch ' + joinpath(self.tmpdir,'txbump')
  633. os.system(cmd)
  634. return t
  635. def txsend(self,sigfile,extra_opts=[]):
  636. t = self.spawn('mmgen-txsend', extra_opts + ['-d',self.tmpdir,sigfile])
  637. self.txsend_ui_common(t,view='t',add_comment='')
  638. return t
  639. def txdo(self,addrfile,wallet):
  640. t = self.txcreate_common(sources=['1'],txdo_args=[wallet])
  641. self.txsign_ui_common(t,view='n',do_passwd=True)
  642. self.txsend_ui_common(t)
  643. return t
  644. def _walletconv_export(self,wf,uargs=[],out_fmt='w',pf=None):
  645. opts = ['-d',self.tmpdir,'-o',out_fmt] + uargs + \
  646. ([],[wf])[bool(wf)] + ([],['-P',pf])[bool(pf)]
  647. t = self.spawn('mmgen-walletconv',opts)
  648. t.license()
  649. if not pf:
  650. icls = get_wallet_cls(ext=get_extension(wf))
  651. t.passphrase(icls.desc,self.wpasswd)
  652. ocls = get_wallet_cls(fmt_code=out_fmt)
  653. if ocls.enc and ocls.type != 'brain':
  654. t.passphrase_new('new '+ocls.desc,self.wpasswd)
  655. t.usr_rand(self.usr_rand_chars)
  656. if ocls.type.startswith('incog'):
  657. m = 'Encrypting random data from your operating system with ephemeral key'
  658. t.expect(m)
  659. t.expect(m)
  660. incog_id = t.expect_getend('New Incog Wallet ID: ')
  661. t.expect(m)
  662. if ocls.type == 'incog_hidden':
  663. self.write_to_tmpfile(incog_id_fn,incog_id)
  664. t.hincog_create(hincog_bytes)
  665. elif ocls.type == 'mmgen':
  666. t.label()
  667. return t.written_to_file(capfirst(ocls.desc)), t
  668. def export_seed(self,wf,out_fmt='seed',pf=None):
  669. f,t = self._walletconv_export(wf,out_fmt=out_fmt,pf=pf)
  670. silence()
  671. wcls = get_wallet_cls(fmt_code=out_fmt)
  672. msg('==> {}: {}'.format(
  673. wcls.desc,
  674. cyan(get_data_from_file( cfg, f, wcls.desc ))
  675. ))
  676. end_silence()
  677. return t
  678. def export_hex(self,wf,out_fmt='mmhex',pf=None):
  679. return self.export_seed(wf,out_fmt=out_fmt,pf=pf)
  680. def export_mnemonic(self,wf):
  681. return self.export_seed(wf,out_fmt='words')
  682. def export_bip39(self,wf):
  683. return self.export_seed(wf,out_fmt='bip39')
  684. def export_incog(self,wf,out_fmt='i',add_args=[]):
  685. uargs = ['-p1',self.usr_rand_arg] + add_args
  686. _,t = self._walletconv_export(wf,out_fmt=out_fmt,uargs=uargs)
  687. return t
  688. def export_incog_hex(self,wf):
  689. return self.export_incog(wf,out_fmt='xi')
  690. # TODO: make outdir and hidden incog compatible (ignore --outdir and warn user?)
  691. def export_incog_hidden(self,wf):
  692. rf = joinpath(self.tmpdir,hincog_fn)
  693. add_args = ['-J',f'{rf},{hincog_offset}']
  694. return self.export_incog(wf,out_fmt='hi',add_args=add_args)
  695. def addrgen_seed(self,wf,_,in_fmt='seed'):
  696. wcls = get_wallet_cls(fmt_code=in_fmt)
  697. stdout = wcls.type == 'seed' # capture output to screen once
  698. t = self.spawn(
  699. 'mmgen-addrgen',
  700. (['-S'] if stdout else []) +
  701. self.segwit_arg +
  702. [ '-i' + in_fmt, '-d', self.tmpdir, wf, self.addr_idx_list ] )
  703. t.license()
  704. t.expect_getend(f'Valid {wcls.desc} for Seed ID ')
  705. vmsg('Comparing generated checksum with checksum from previous address file')
  706. verify_checksum_or_exit(
  707. self._get_addrfile_checksum(),
  708. t.expect_getend(r'Checksum for address data .*?: ',regex=True) )
  709. if not stdout:
  710. t.no_overwrite()
  711. t.req_exit_val = 1
  712. return t
  713. def addrgen_hex(self,wf,_,in_fmt='mmhex'):
  714. return self.addrgen_seed(wf,_,in_fmt=in_fmt)
  715. def addrgen_mnemonic(self,wf,_):
  716. return self.addrgen_seed(wf,_,in_fmt='words')
  717. def addrgen_incog(self,wf=[],_='',in_fmt='i',args=[]):
  718. t = self.spawn('mmgen-addrgen', args + self.segwit_arg + ['-i'+in_fmt,'-d',self.tmpdir]+
  719. ([],[wf])[bool(wf)] + [self.addr_idx_list])
  720. t.license()
  721. t.expect_getend('Incog Wallet ID: ')
  722. wcls = get_wallet_cls(fmt_code=in_fmt)
  723. t.hash_preset(wcls.desc,'1')
  724. t.passphrase(rf'{wcls.desc} \w{{8}}',self.wpasswd)
  725. vmsg('Comparing generated checksum with checksum from address file')
  726. chk = t.expect_getend(r'Checksum for address data .*?: ',regex=True)
  727. verify_checksum_or_exit(self._get_addrfile_checksum(),chk)
  728. t.no_overwrite()
  729. t.req_exit_val = 1
  730. return t
  731. def addrgen_incog_hex(self,wf,_):
  732. return self.addrgen_incog(wf,'',in_fmt='xi')
  733. def addrgen_incog_hidden(self,wf,_):
  734. rf = joinpath(self.tmpdir,hincog_fn)
  735. return self.addrgen_incog([],'',in_fmt='hi',
  736. args=['-H',f'{rf},{hincog_offset}','-l',str(hincog_seedlen)])
  737. def txsign_keyaddr(self,keyaddr_file,txfile):
  738. t = self.spawn('mmgen-txsign', ['-d',self.tmpdir,'-p1','-M',keyaddr_file,txfile])
  739. t.license()
  740. t.view_tx('n')
  741. t.do_decrypt_ka_data(pw=self.kapasswd)
  742. self.txsign_end(t)
  743. return t
  744. def txcreate_ni(self,addrfile):
  745. return self.txcreate_common(sources=['1'],cmdline_inputs=True,add_args=['--yes'])
  746. def walletgen2(self,del_dw_run='dummy'):
  747. return self.walletgen(seed_len=128)
  748. def addrgen2(self,wf):
  749. return self.addrgen(wf)
  750. def txcreate2(self,addrfile):
  751. return self.txcreate_common(sources=['2'])
  752. def txsign2(self,wf1,txf1,wf2,txf2):
  753. t = self.spawn('mmgen-txsign', ['-d',self.tmpdir,txf1,wf1,txf2,wf2])
  754. t.license()
  755. for cnum,wf in (('1',wf1),('2',wf2)):
  756. wcls = get_wallet_cls(ext=get_extension(wf))
  757. t.view_tx('n')
  758. t.passphrase(wcls.desc,self.cfgs[cnum]['wpasswd'])
  759. self.txsign_end(t,cnum)
  760. return t
  761. def export_mnemonic2(self,wf):
  762. return self.export_mnemonic(wf)
  763. def walletgen3(self,del_dw_run='dummy'):
  764. return self.walletgen()
  765. def addrgen3(self,wf):
  766. return self.addrgen(wf)
  767. def txcreate3(self,addrfile1,addrfile2):
  768. return self.txcreate_common(sources=['1','3'])
  769. def txsign3(self,wf1,wf2,txf2):
  770. t = self.spawn('mmgen-txsign', ['-d',self.tmpdir,wf1,wf2,txf2])
  771. t.license()
  772. t.view_tx('n')
  773. for cnum,wf in (('1',wf1),('3',wf2)):
  774. wcls = get_wallet_cls(ext=get_extension(wf))
  775. t.passphrase(wcls.desc,self.cfgs[cnum]['wpasswd'])
  776. self.txsign_end(t)
  777. return t
  778. walletgen14 = walletgen
  779. addrgen14 = CmdTestShared.addrgen
  780. keyaddrgen14 = CmdTestShared.keyaddrgen
  781. def walletgen4(self,del_dw_run='dummy'):
  782. bwf = joinpath(self.tmpdir,self.bw_filename)
  783. make_brainwallet_file(bwf)
  784. seed_len = str(self.seed_len)
  785. args = ['-d',self.tmpdir,'-p1',self.usr_rand_arg,'-l'+seed_len,'-ibw']
  786. t = self.spawn('mmgen-walletconv', args + [bwf])
  787. t.license()
  788. wcls = MMGenWallet
  789. t.passphrase_new('new ' +wcls.desc,self.wpasswd)
  790. t.usr_rand(self.usr_rand_chars)
  791. t.label()
  792. t.written_to_file(capfirst(wcls.desc))
  793. return t
  794. def addrgen4(self,wf):
  795. return self.addrgen(wf)
  796. def txcreate4(self,f1,f2,f3,f4,f5,f6):
  797. return self.txcreate_common(
  798. sources = ['1', '2', '3', '4', '14'],
  799. non_mmgen_input = '4',
  800. do_label = True,
  801. view = 'y',
  802. tweaks = ['confirm_non_mmgen'] )
  803. def txsign4(self,f1,f2,f3,f4,f5,f6):
  804. non_mm_file = joinpath(self.tmpdir,non_mmgen_fn)
  805. add_args = [
  806. '-d', self.tmpdir,
  807. '-i', 'brain',
  808. '-b' + self.bw_params,
  809. '-p1',
  810. '--keys-from-file=' + non_mm_file,
  811. '--mmgen-keys-from-file=' + f6,
  812. f1, f2, f3, f4, f5 ]
  813. t = self.spawn('mmgen-txsign',add_args)
  814. t.license()
  815. t.view_tx('t')
  816. t.do_decrypt_ka_data(pw=self.cfgs['14']['kapasswd'])
  817. for cnum,wcls in (('1',IncogWallet),('3',MMGenWallet)):
  818. t.passphrase(wcls.desc,self.cfgs[cnum]['wpasswd'])
  819. self.txsign_end(t,has_label=True)
  820. return t
  821. def txdo4(self,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12):
  822. non_mm_file = joinpath(self.tmpdir,non_mmgen_fn)
  823. add_args = [
  824. '-d', self.tmpdir,
  825. '-i', 'brain',
  826. '-b'+self.bw_params,
  827. '-p1',
  828. '--keys-from-file=' + non_mm_file,
  829. '--mmgen-keys-from-file=' + f12 ]
  830. self.get_file_with_ext('sigtx',delete_all=True) # delete tx signed by txsign4
  831. t = self.txcreate_common(sources=['1','2','3','4','14'],
  832. non_mmgen_input='4',do_label=True,txdo_args=[f7,f8,f9,f10],add_args=add_args)
  833. for cnum,wcls in (('1',IncogWallet),('3',MMGenWallet)):
  834. t.passphrase(wcls.desc,self.cfgs[cnum]['wpasswd'])
  835. self.txsign_ui_common(t)
  836. self.txsend_ui_common(t)
  837. cmd = 'touch ' + joinpath(self.tmpdir,'txdo')
  838. os.system(cmd)
  839. return t
  840. def txbump4(self,f1,f2,f3,f4,f5,f6,f7,f8,f9): # f7:txfile,f9:'txdo'
  841. non_mm_file = joinpath(self.tmpdir,non_mmgen_fn)
  842. return self.txbump(f7,prepend_args=['-p1','-k',non_mm_file,'-M',f1],seed_args=[f2,f3,f4,f5,f6,f8])
  843. def walletgen5(self,del_dw_run='dummy'):
  844. return self.walletgen()
  845. def addrgen5(self,wf):
  846. return self.addrgen(wf)
  847. def txcreate5(self,addrfile):
  848. return self.txcreate_common(
  849. sources = ['20'],
  850. non_mmgen_input = '20',
  851. non_mmgen_input_compressed = False,
  852. tweaks = ['confirm_non_mmgen'] )
  853. def txsign5(self,wf,txf,bad_vsize=True,add_args=[]):
  854. non_mm_file = joinpath(self.tmpdir,non_mmgen_fn)
  855. t = self.spawn('mmgen-txsign', add_args + ['-d',self.tmpdir,'-k',non_mm_file,txf,wf])
  856. t.license()
  857. t.view_tx('n')
  858. wcls = get_wallet_cls(ext=get_extension(wf))
  859. t.passphrase(wcls.desc,self.cfgs['20']['wpasswd'])
  860. if bad_vsize:
  861. t.expect('Estimated transaction vsize')
  862. t.expect('1 transaction could not be signed')
  863. exit_val = 2
  864. else:
  865. t.do_comment(False)
  866. t.expect('Save signed transaction? (Y/n): ','y')
  867. exit_val = 0
  868. t.req_exit_val = exit_val
  869. return t
  870. def walletgen6(self,del_dw_run='dummy'):
  871. return self.walletgen()
  872. def addrgen6(self,wf):
  873. return self.addrgen(wf)
  874. def txcreate6(self,addrfile):
  875. return self.txcreate_common(
  876. sources = ['21'],
  877. non_mmgen_input = '21',
  878. non_mmgen_input_compressed = False,
  879. add_args = ['--vsize-adj=1.08'],
  880. tweaks = ['confirm_non_mmgen'] )
  881. def txsign6(self,wf,txf):
  882. return self.txsign5(wf,txf,bad_vsize=False,add_args=['--vsize-adj=1.08'])