rune.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #!/usr/bin/env python3
  2. import os
  3. from collections import namedtuple
  4. from decimal import Decimal
  5. from mmgen.cfg import Config
  6. from mmgen.util import pp_fmt, ymsg
  7. from mmgen.proto.btc.common import hash160
  8. from mmgen.proto.cosmos.tx.protobuf import RawTx, SignDoc
  9. from mmgen.proto.rune.tx.protobuf import (
  10. RuneTx,
  11. build_tx,
  12. build_swap_tx,
  13. tx_info,
  14. send_tx_parms,
  15. deposit_tx_parms,
  16. swap_tx_parms)
  17. from ..include.common import vmsg, silence, end_silence
  18. test_cfg = Config({'coin': 'rune', 'test_suite': True})
  19. altcoin_dep = True
  20. _pv = namedtuple('parse_vector', ['fn', 'txid', 'parms', 'null_fee'], defaults=[None])
  21. parse_vectors = [
  22. _pv(
  23. 'mainnet-tx-msgsend1.binpb',
  24. '36f91982c1911fe1aa66b44eed60e29175e5b8ae3301feef9158b7617779b00e',
  25. send_tx_parms(
  26. 'thor1t60f02r8jvzjrhtnjgfj4ne6rs5wjnejwmj7fh',
  27. 'thor166n4w5039meulfa3p6ydg60ve6ueac7tlt0jws',
  28. '12613.15290000',
  29. 8000000,
  30. 45060,
  31. 302033,
  32. pubkey = '02f9cbb8409443ccf043f26d8f91c2550d2578ecc49bb3ad89d4e21a7882bf1e23',
  33. signature = 'd44b2e0c7546c5fae24a2c829757f49cce1bb29553f7e1a2f87c1ac2f1c46e22' # r
  34. '509d765fc605d85e8967639864622ebc7c39a1a93fc20cf0fe5d703c4aa3636d')), # s
  35. _pv(
  36. 'mainnet-tx-msgdeposit1.binpb',
  37. '1089bbd54746bbc6a40e264d3ce8085561978739094c9c5aac59c569b4c28ba9',
  38. deposit_tx_parms(
  39. 'THOR', 'RUNE', 'RUNE',
  40. 'thor1lukwlve7hayy66qrdkp4k7sh0emjqwergy7tl3',
  41. '299.23861844',
  42. 600000000,
  43. 125632,
  44. 348388,
  45. decimals = 8,
  46. memo = '=:LTC~LTC:thor1lukwlve7hayy66qrdkp4k7sh0emjqwergy7tl3:605926421/0/1',
  47. pubkey = '03da157f891abfe7822efb91f59667aa6cc6c3768a7e280caeb9ae243c969eb3e7',
  48. signature = '869399bcc2ccb9c9c286bdf214439ad132221cb8206547ceb012e06efbc3ff3e' # r
  49. '0ecc1ba4106702fb5b60cd7a8b94193ea71af5e6e860d978c49a6a63d97e4ded')), # s
  50. _pv(
  51. 'mainnet-tx-msgdeposit2.binpb',
  52. '44f45b91e97558e63a11758ac3c186196b9b46f6331f32eff1256888ea879b62',
  53. deposit_tx_parms(
  54. 'ETH', 'USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7', 'USDT',
  55. 'thor1xxncvuptvmgcl5ep7rry3xehtw97jsg9uyv6rn',
  56. '500.00000000',
  57. 50000000,
  58. 88176,
  59. 104625,
  60. decimals = None,
  61. synth = False,
  62. trade = True,
  63. memo = '=:AVAX~AVAX:thor1xxncvuptvmgcl5ep7rry3xehtw97jsg9uyv6rn:2113883178',
  64. pubkey = '02a6e97e3f20809511500d8895117d4344badda9e6af4216d41b10a105d1070254',
  65. signature = 'b0673ab89781199d35b94051f26db30996f055abd71804d67fe4bdf33934bdb9' # r
  66. '30d830675d398c6d042328ef681bf1a23e856ed0ab33d948ea149489400db953'), # s
  67. null_fee = True),
  68. _pv(
  69. 'mainnet-tx-msgdeposit3.binpb',
  70. '02d2fb2f2e5ac00ad4a31c37ffc43b72963f93598f8b3c8f4d3932c2e950b459',
  71. deposit_tx_parms(
  72. 'ETH', 'USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48', 'USDC',
  73. 'thor1lukwlve7hayy66qrdkp4k7sh0emjqwergy7tl3',
  74. '2425.75973697',
  75. 600000000,
  76. 125632,
  77. 375988,
  78. decimals = 8,
  79. synth = None,
  80. trade = True,
  81. memo = '=:THOR.RUNE:thor1lukwlve7hayy66qrdkp4k7sh0emjqwergy7tl3:127025748855/0/1',
  82. pubkey = '03da157f891abfe7822efb91f59667aa6cc6c3768a7e280caeb9ae243c969eb3e7',
  83. signature = 'be8324f6a1535b971d63715532e2e42ee3c35c05b81ed9b6bccd9a1765688eca'
  84. '4ca00a66119b07c5168c6c78e22299becc82d5f311ee79ae9183776b0dff3269'))
  85. ]
  86. _bv = namedtuple('build_vector', ['txid', 'parms', 'null_fee'], defaults=[None])
  87. build_vectors = [
  88. _bv(
  89. '3939612d0ddc55fd4d1c6ef118d1b2085a6655cb57d55ac9efd658467e039e0c',
  90. send_tx_parms(
  91. 'thor1tx3nm6xfynq3re5ehtm6530z0pah9qjeu0r9nd',
  92. 'thor1j5u6vlr8kzt76fe7896hsmurkhgn68j0z4qa6w',
  93. '123.456789',
  94. 8000000,
  95. 12345,
  96. 37,
  97. wifkey = 'L5nWojqqMLq7wh3CfhxUNYQ38acABD6sUao9dfb8i5B5wSefCJXe')),
  98. _bv(
  99. '0d41e0ee40cd18a991cd8f0ef0e60e4c5bea898c53d54e00b6dddc0c9ce7edb7',
  100. deposit_tx_parms(
  101. 'THOR', 'RUNE', 'RUNE',
  102. 'thor18ug6p4zs5dsy0m3u69gf5md5ssdg8hqkk8aya4',
  103. '123.456789',
  104. 8000000,
  105. 12345,
  106. 37,
  107. decimals = 8,
  108. memo = '=:MEMO',
  109. wifkey = 'Ky9bSjPUD35uUaY3JReXiESivnfxV6rLMsW1wTFyvVZwYXpX95vF'))
  110. ]
  111. swap_build_vectors = [
  112. _bv(
  113. '0d41e0ee40cd18a991cd8f0ef0e60e4c5bea898c53d54e00b6dddc0c9ce7edb7',
  114. swap_tx_parms(
  115. 'thor18ug6p4zs5dsy0m3u69gf5md5ssdg8hqkk8aya4',
  116. '123.456789',
  117. 8000000,
  118. 12345,
  119. 37,
  120. memo = '=:MEMO',
  121. wifkey = 'Ky9bSjPUD35uUaY3JReXiESivnfxV6rLMsW1wTFyvVZwYXpX95vF'))
  122. ]
  123. def test_tx(src, cfg, vec):
  124. proto = cfg._proto
  125. parms = vec.parms._replace(amt=Decimal(vec.parms.amt))
  126. if parms.pubkey:
  127. parms = parms._replace(
  128. pubkey = bytes.fromhex(parms.pubkey),
  129. signature = bytes.fromhex(parms.signature))
  130. assert src in ('parse', 'build', 'swapbuild')
  131. if src == 'parse':
  132. tx_in = open(os.path.join('test/ref/thorchain', vec.fn), 'br').read()
  133. tx = RuneTx.loads(tx_in)
  134. if not parms.from_addr:
  135. ymsg(f'Warning: missing test vector data for {vec.fn}')
  136. assert bytes(tx) == tx_in
  137. elif src == 'build':
  138. tx = build_tx(cfg, proto, parms, null_fee=vec.null_fee)
  139. elif src == 'swapbuild':
  140. tx = build_swap_tx(cfg, proto, parms)
  141. vmsg(pp_fmt(tx))
  142. msg_type = 'MsgSend' if tx.body.messages[0].id == '/types.MsgSend' else 'MsgDeposit'
  143. vmsg('\n TX info:\n ' + '\n '.join(tx_info(tx, proto)) + '\n')
  144. tx.verify_sig(proto, parms.account_number)
  145. pubkey = tx.authInfo.signerInfos[0].publicKey.key.data
  146. assert hash160(pubkey) == getattr(
  147. tx.body.messages[0].body,
  148. 'fromAddress' if msg_type == 'MsgSend' else 'signer')
  149. assert tx.txid == vec.txid, tx.txid
  150. if src == 'parse' and parms.from_addr:
  151. built_tx = build_tx(cfg, proto, parms, null_fee=vec.null_fee)
  152. addr_from_pubkey = proto.encode_addr_bech32x(hash160(pubkey))
  153. assert addr_from_pubkey == parms.from_addr
  154. assert bytes(built_tx) == tx_in
  155. raw_tx = RawTx(bytes(tx.body), bytes(tx.authInfo), tx.signatures)
  156. assert bytes(raw_tx) == bytes(RawTx.loads(tx_in))
  157. assert bytes(raw_tx) == bytes(tx.raw)
  158. assert tx_in == bytes(tx)
  159. class unit_tests:
  160. def txparse(self, name, ut, desc='transaction parsing and signature verification'):
  161. for vec in parse_vectors:
  162. test_tx('parse', test_cfg, vec)
  163. return True
  164. def txbuild(self, name, ut, desc='transaction building and signing (MsgSend, MsgDeposit)'):
  165. for vec in build_vectors:
  166. test_tx('build', test_cfg, vec)
  167. return True
  168. def swaptxbuild(self, name, ut, desc='transaction building and signing (Swap TX)'):
  169. for vec in swap_build_vectors:
  170. test_tx('swapbuild', test_cfg, vec)
  171. return True
  172. def rpc(self, name, ut, desc='remote RPC operations'):
  173. import sys, asyncio
  174. from mmgen.rpc import rpc_init
  175. from ..cmdtest_d.httpd.thornode.rpc import ThornodeRPCServer
  176. silence()
  177. regtest_cfg = Config({'coin': 'rune', 'regtest': True, 'test_suite': True})
  178. end_silence()
  179. thornode_server = ThornodeRPCServer()
  180. thornode_server.start()
  181. addr = 'thor1lukwlve7hayy66qrdkp4k7sh0emjqwergy7tl3'
  182. txhash = 'abcdef01' * 8
  183. txbytes = open('test/ref/thorchain/mainnet-tx-msgsend1.binpb', 'rb').read()
  184. async def main():
  185. rpc = await rpc_init(regtest_cfg)
  186. res = rpc.get_account_info(addr)
  187. assert res['address'] == addr
  188. assert res['account_number']
  189. assert res['sequence']
  190. res = rpc.get_tx_info(txhash)
  191. assert res['hash'] == txhash.upper()
  192. res = rpc.tx_op(txbytes.hex(), op='check_tx')
  193. assert res['code'] == 0
  194. asyncio.run(main())
  195. return True