ct_automount.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
  4. # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. test.cmdtest_py_d.ct_automount: autosigning with automount tests for the cmdtest.py test suite
  12. """
  13. import os, time
  14. from pathlib import Path
  15. from .ct_autosign import CmdTestAutosignThreaded
  16. from .ct_regtest import CmdTestRegtestBDBWallet, rt_pw
  17. from .common import get_file_with_ext
  18. from ..include.common import cfg
  19. class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet):
  20. 'automounted transacting operations via regtest mode'
  21. networks = ('btc', 'bch', 'ltc')
  22. tmpdir_nums = [49]
  23. extra_spawn_args = []
  24. rtFundAmt = None # pylint
  25. rt_data = {
  26. 'rtFundAmt': {'btc':'500', 'bch':'500', 'ltc':'5500'},
  27. }
  28. cmd_group = (
  29. ('setup', 'regtest mode setup'),
  30. ('walletgen_alice', 'wallet generation (Alice)'),
  31. ('addrgen_alice', 'address generation (Alice)'),
  32. ('addrimport_alice', 'importing Alice’s addresses'),
  33. ('fund_alice', 'funding Alice’s wallet'),
  34. ('generate', 'mining a block'),
  35. ('alice_bal1', 'checking Alice’s balance'),
  36. ('alice_txcreate1', 'creating a transaction'),
  37. ('alice_txcreate_bad_have_unsigned', 'creating the transaction again (error)'),
  38. ('copy_wallet', 'copying Alice’s wallet'),
  39. ('alice_run_autosign_setup', 'running ‘autosign setup’ (with default wallet)'),
  40. ('autosign_start_thread', 'starting autosign wait loop'),
  41. ('alice_txstatus1', 'getting transaction status (unsigned)'),
  42. ('alice_txstatus2', 'getting transaction status (unsent)'),
  43. ('alice_txsend1', 'sending a transaction, editing comment'),
  44. ('alice_txstatus3', 'getting transaction status (in mempool)'),
  45. ('alice_txsend_bad_no_unsent', 'sending the transaction again (error)'),
  46. ('generate', 'mining a block'),
  47. ('alice_txstatus4', 'getting transaction status (one confirmation)'),
  48. ('alice_txcreate2', 'creating a transaction'),
  49. ('alice_txsend_abort1', 'aborting the transaction (raw only)'),
  50. ('alice_txsend_abort2', 'aborting the transaction again (error)'),
  51. ('alice_txcreate3', 'creating a transaction'),
  52. ('alice_txsend_abort3', 'aborting the transaction (user exit)'),
  53. ('alice_txsend_abort4', 'aborting the transaction (raw + signed)'),
  54. ('alice_txsend_abort5', 'aborting the transaction again (error)'),
  55. ('generate', 'mining a block'),
  56. ('alice_txcreate4', 'creating a transaction'),
  57. ('alice_txbump1', 'bumping the unsigned transaction (error)'),
  58. ('alice_txbump2', 'bumping the unsent transaction (error)'),
  59. ('alice_txsend2', 'sending the transaction'),
  60. ('alice_txbump3', 'bumping the transaction'),
  61. ('alice_txsend3', 'sending the bumped transaction'),
  62. ('autosign_kill_thread', 'stopping autosign wait loop'),
  63. ('stop', 'stopping regtest daemon'),
  64. ('txview', 'viewing transactions'),
  65. )
  66. def __init__(self, trunner, cfgs, spawn):
  67. self.coins = [cfg.coin.lower()]
  68. CmdTestAutosignThreaded.__init__(self, trunner, cfgs, spawn)
  69. CmdTestRegtestBDBWallet.__init__(self, trunner, cfgs, spawn)
  70. if trunner == None:
  71. return
  72. self.opts.append('--alice')
  73. def _alice_txcreate(self, chg_addr, opts=[], exit_val=0):
  74. self.insert_device_online()
  75. sid = self._user_sid('alice')
  76. t = self.spawn(
  77. 'mmgen-txcreate',
  78. opts
  79. + ['--alice', '--autosign']
  80. + [f'{self.burn_addr},1.23456', f'{sid}:{chg_addr}'])
  81. if exit_val:
  82. t.read()
  83. self.remove_device_online()
  84. t.req_exit_val = exit_val
  85. return t
  86. t = self.txcreate_ui_common(
  87. t,
  88. inputs = '1',
  89. interactive_fee = '32s',
  90. file_desc = 'Unsigned automount transaction')
  91. t.read()
  92. self.remove_device_online()
  93. return t
  94. def alice_txcreate1(self):
  95. return self._alice_txcreate(chg_addr='C:5')
  96. def alice_txcreate2(self):
  97. return self._alice_txcreate(chg_addr='L:5')
  98. alice_txcreate3 = alice_txcreate2
  99. def alice_txcreate4(self):
  100. if cfg.coin == 'BCH':
  101. return 'skip'
  102. return self._alice_txcreate(chg_addr='L:4')
  103. def _alice_txsend_abort(self, err=False, user_exit=False, del_expect=[]):
  104. self.insert_device_online()
  105. t = self.spawn(
  106. 'mmgen-txsend',
  107. ['--quiet', '--abort'])
  108. if err:
  109. t.expect('No unsent transactions')
  110. t.req_exit_val = 2
  111. else:
  112. t.expect('(y/N): ', 'n' if user_exit else 'y')
  113. if user_exit:
  114. t.expect('Exiting at user request')
  115. t.req_exit_val = 1
  116. else:
  117. for pat in del_expect:
  118. t.expect(pat, regex=True)
  119. self.remove_device_online()
  120. return t
  121. def alice_txsend_abort1(self):
  122. return self._alice_txsend_abort(del_expect=['Shredding .*arawtx'])
  123. def alice_txsend_abort2(self):
  124. return self._alice_txsend_abort(err=True)
  125. def alice_txsend_abort3(self):
  126. return self._alice_txsend_abort(user_exit=True)
  127. def alice_txsend_abort4(self):
  128. self._wait_signed('transaction')
  129. return self._alice_txsend_abort(del_expect=[r'Shredding .*arawtx', r'Shredding .*asigtx'])
  130. alice_txsend_abort5 = alice_txsend_abort2
  131. def alice_txcreate_bad_have_unsigned(self):
  132. return self._alice_txcreate(chg_addr='C:5', exit_val=2)
  133. def copy_wallet(self):
  134. self.spawn('', msg_only=True)
  135. if cfg.coin == 'BTC':
  136. return 'skip_msg'
  137. src = Path(self.tr.data_dir, 'regtest', cfg.coin.lower(), 'alice')
  138. dest = Path(self.tr.data_dir, 'regtest', 'btc', 'alice')
  139. dest.mkdir(parents=True, exist_ok=True)
  140. wf = Path(get_file_with_ext(src, 'mmdat')).absolute()
  141. link_path = dest / wf.name
  142. if not link_path.exists():
  143. link_path.symlink_to(wf)
  144. return 'ok'
  145. def alice_run_autosign_setup(self):
  146. self.insert_device()
  147. t = self.run_setup(mn_type='default', use_dfl_wallet=True, passwd=rt_pw)
  148. t.read()
  149. self.remove_device()
  150. return t
  151. def alice_txsend1(self):
  152. return self._alice_txsend('This one’s worth a comment', no_wait=True)
  153. def alice_txsend2(self):
  154. if cfg.coin == 'BCH':
  155. return 'skip'
  156. return self._alice_txsend()
  157. def alice_txsend3(self):
  158. if cfg.coin == 'BCH':
  159. return 'skip'
  160. return self._alice_txsend()
  161. def _alice_txstatus(self, expect, exit_val=None):
  162. self.insert_device_online()
  163. t = self.spawn(
  164. 'mmgen-txsend',
  165. ['--alice', '--autosign', '--status', '--verbose'])
  166. t.expect(expect)
  167. self.remove_device_online()
  168. if exit_val:
  169. t.req_exit_val = exit_val
  170. return t
  171. def alice_txstatus1(self):
  172. return self._alice_txstatus('unsigned', 1)
  173. def alice_txstatus2(self):
  174. self._wait_signed('transaction')
  175. return self._alice_txstatus('unsent', 1)
  176. def alice_txstatus3(self):
  177. return self._alice_txstatus('in mempool')
  178. def alice_txstatus4(self):
  179. return self._alice_txstatus('1 confirmation')
  180. def _alice_txsend(self, comment=None, no_wait=False):
  181. if not no_wait:
  182. self._wait_signed('transaction')
  183. self.insert_device_online()
  184. t = self.spawn('mmgen-txsend', ['--alice', '--quiet', '--autosign'])
  185. t.view_tx('t')
  186. t.do_comment(comment)
  187. self._do_confirm_send(t, quiet=True)
  188. t.written_to_file('Sent automount transaction')
  189. t.read()
  190. self.remove_device_online()
  191. return t
  192. def alice_txsend_bad_no_unsent(self):
  193. self.insert_device_online()
  194. t = self.spawn('mmgen-txsend', ['--quiet', '--autosign'])
  195. t.expect('No unsent transactions')
  196. t.read()
  197. t.req_exit_val = 2
  198. self.remove_device_online()
  199. return t
  200. def _alice_txbump(self, bad_tx_desc=None):
  201. if cfg.coin == 'BCH':
  202. return 'skip'
  203. self.insert_device_online()
  204. t = self.spawn(
  205. 'mmgen-txbump',
  206. ['--alice', '--autosign'])
  207. if bad_tx_desc:
  208. t.expect('Only sent transactions')
  209. t.expect(bad_tx_desc)
  210. t.req_exit_val = 1
  211. else:
  212. t.expect(f'to deduct the fee from .* change output\): ', '\n', regex=True)
  213. t.expect(r'(Y/n): ', 'y') # output OK?
  214. t.expect('transaction fee: ', '200s\n')
  215. t.expect(r'(Y/n): ', 'y') # fee OK?
  216. t.expect(r'(y/N): ', '\n') # add comment?
  217. t.expect(r'(y/N): ', 'y') # save?
  218. t.read()
  219. self.remove_device_online()
  220. return t
  221. def alice_txbump1(self):
  222. return self._alice_txbump(bad_tx_desc='unsigned transaction')
  223. def alice_txbump2(self):
  224. self._wait_signed('transaction')
  225. return self._alice_txbump(bad_tx_desc='unsent transaction')
  226. def alice_txbump3(self):
  227. return self._alice_txbump()