rune.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2025 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_d.rune: THORChain RUNE tests for the cmdtest.py test suite
  12. """
  13. from hashlib import md5
  14. from mmgen.fileutil import get_data_from_file
  15. from .include.common import dfl_sid, dfl_words_file
  16. from .include.proxy import TestProxy
  17. from .httpd.thornode.rpc import ThornodeRPCServer
  18. from .ethdev import CmdTestEthdevMethods
  19. from .base import CmdTestBase
  20. from .shared import CmdTestShared
  21. from .swap import CmdTestSwapMethods
  22. class CmdTestRune(CmdTestEthdevMethods, CmdTestBase, CmdTestShared):
  23. 'THORChain RUNE tracking wallet and transacting operations'
  24. networks = ('rune',)
  25. passthru_opts = ('coin', 'http_timeout')
  26. tmpdir_nums = [50]
  27. color = True
  28. menu_prompt = 'efresh balance:\b'
  29. txhex_chksum = '83f85785'
  30. cmd_group_in = (
  31. ('subgroup.init', []),
  32. ('subgroup.main', ['init']),
  33. ('rpc_server_stop', 'stopping the Thornode RPC server'),
  34. )
  35. cmd_subgroups = {
  36. 'init': (
  37. 'initializing wallets',
  38. ('addrgen', 'generating addresses'),
  39. ('addrimport', 'importing addresses'),
  40. ),
  41. 'main': (
  42. 'tracking wallet and transaction operations',
  43. ('twview', 'viewing unspent outputs in tracking wallet'),
  44. ('bal_refresh', 'refreshing address balance in tracking wallet'),
  45. ('txcreate1', 'creating a transaction'),
  46. ('txsign1', 'signing the transaction'),
  47. ('txsend1_test', 'testing whether the transaction can be sent'),
  48. ('txsend1', 'sending the transaction'),
  49. ('txhex1', 'dumping the transaction hex'),
  50. ),
  51. }
  52. def __init__(self, cfg, trunner, cfgs, spawn):
  53. CmdTestBase.__init__(self, cfg, trunner, cfgs, spawn)
  54. if trunner is None:
  55. return
  56. self.eth_opts = [f'--outdir={self.tmpdir}', '--regtest=1', '--quiet']
  57. self.eth_opts_noquiet = [f'--outdir={self.tmpdir}', '--regtest=1']
  58. self.rune_opts = self.eth_opts
  59. from mmgen.protocol import init_proto
  60. self.proto = init_proto(cfg, network_id=self.proto.coin + '_rt', need_amt=True)
  61. self.spawn_env['MMGEN_BOGUS_SEND'] = ''
  62. self.rpc_server = ThornodeRPCServer()
  63. self.rpc_server.start()
  64. TestProxy(self, cfg)
  65. self.txhex_file = f'{self.tmpdir}/tx_dump.hex'
  66. def addrgen(self):
  67. return self._addrgen()
  68. def addrimport(self):
  69. return self._addrimport()
  70. def twview(self):
  71. return self.spawn('mmgen-tool', self.rune_opts + ['twview'])
  72. def bal_refresh(self):
  73. t = self.spawn('mmgen-tool', self.rune_opts + ['listaddresses', 'interactive=1'])
  74. t.expect(self.menu_prompt, 'R')
  75. t.expect('menu): ', '3\n')
  76. t.expect('(y/N): ', 'y')
  77. t.expect(r'Total RUNE: \S*\D9876.54321321\D', regex=True)
  78. t.expect('address #3 refreshed')
  79. t.expect(self.menu_prompt, 'q')
  80. return t
  81. def txcreate1(self):
  82. t = self.spawn('mmgen-txcreate', self.rune_opts + ['98831F3A:X:2,54.321'])
  83. t.expect(self.menu_prompt, 'q')
  84. t.expect('spend from: ', '3\n')
  85. t.expect('(y/N): ', 'y') # add comment?
  86. t.expect('Comment: ', 'RUNE Boy\n')
  87. t.expect('view: ', 'y')
  88. t.expect('to continue: ', 'z')
  89. t.expect('(y/N): ', 'y') # save?
  90. t.written_to_file('Unsigned transaction')
  91. return t
  92. def txsign1(self):
  93. return self.txsign_ui_common(
  94. self.spawn(
  95. 'mmgen-txsign',
  96. self.rune_opts + [self.get_file_with_ext('rawtx'), dfl_words_file],
  97. no_passthru_opts = ['coin']),
  98. has_label = True)
  99. def txsend1_test(self):
  100. return self._txsend(add_opts=['--test', f'--proxy=localhost:{TestProxy.port}'], test=True)
  101. def txsend1(self):
  102. return self._txsend()
  103. def _txsend(self, add_opts=[], *, test=False, dump_hex=False):
  104. t = self.spawn(
  105. 'mmgen-txsend',
  106. self.rune_opts + add_opts + [self.get_file_with_ext('sigtx')],
  107. no_passthru_opts = ['coin'])
  108. t.expect('view: ', 'y')
  109. t.expect('to continue: ', 'z')
  110. t.expect('(y/N): ', 'n') # edit comment?
  111. if dump_hex:
  112. t.written_to_file('hex data')
  113. elif test:
  114. t.expect('can be sent')
  115. else:
  116. t.expect('to confirm: ', 'YES\n')
  117. t.expect('Transaction sent: ')
  118. if t.expect(['written to file', 'txid mismatch']):
  119. self.tr.warn('txid mismatch')
  120. return 'ok'
  121. return t
  122. def txhex1(self):
  123. t = self._txsend(add_opts=[f'--dump-hex={self.txhex_file}'], dump_hex=True)
  124. t.read()
  125. txhex = get_data_from_file(self.cfg, self.txhex_file, silent=True)
  126. if md5(txhex.encode()).hexdigest()[:8] != self.txhex_chksum:
  127. self.tr.warn('txid mismatch')
  128. return t
  129. def rpc_server_stop(self):
  130. return CmdTestSwapMethods._thornode_server_stop(
  131. self, attrname='rpc_server', name='Thornode RPC server')