ut_rpc.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #!/usr/bin/env python3
  2. """
  3. test.unit_tests_d.ut_rpc: RPC unit test for the MMGen suite
  4. """
  5. from mmgen.common import *
  6. from mmgen.protocol import init_proto
  7. from mmgen.rpc import rpc_init
  8. from mmgen.daemon import CoinDaemon
  9. from mmgen.proto.xmr.rpc import MoneroRPCClient,MoneroRPCClientRaw,MoneroWalletRPCClient
  10. from mmgen.proto.xmr.daemon import MoneroWalletDaemon
  11. def cfg_file_auth_test(proto,d):
  12. qmsg(cyan(f'\n Testing authentication with credentials from {d.cfg_file}:'))
  13. d.remove_datadir() # removes cookie file to force authentication from cfg file
  14. os.makedirs(d.network_datadir)
  15. cf = os.path.join(d.datadir,d.cfg_file)
  16. with open(cf,'a') as fp:
  17. fp.write('\nrpcuser = ut_rpc\nrpcpassword = ut_rpc_passw0rd\n')
  18. d.flag.keep_cfg_file = True
  19. d.start()
  20. async def do():
  21. rpc = await rpc_init(proto)
  22. assert rpc.auth.user == 'ut_rpc', f'{rpc.auth.user}: user is not ut_rpc!'
  23. run_session(do())
  24. d.stop()
  25. def print_daemon_info(rpc):
  26. def fmt_dict(d):
  27. return '\n ' + '\n '.join( pp_fmt(d).split('\n') ) + '\n'
  28. msg(f"""
  29. DAEMON VERSION: {rpc.daemon_version} [{rpc.daemon_version_str}]
  30. CAPS: {rpc.caps}
  31. NETWORK: {rpc.proto.coin} {rpc.proto.network.upper()}
  32. CHAIN: {rpc.chain}
  33. BLOCKCOUNT: {rpc.blockcount}
  34. CUR_DATE: {rpc.cur_date} [{make_timestr(rpc.cur_date)}]
  35. """.rstrip())
  36. if rpc.proto.base_proto == 'Bitcoin':
  37. msg(f"""
  38. NETWORKINFO: {fmt_dict(rpc.cached["networkinfo"])}
  39. BLOCKCHAININFO: {fmt_dict(rpc.cached["blockchaininfo"])}
  40. DEPLOYMENTINFO: {fmt_dict(rpc.cached["deploymentinfo"])}
  41. """.rstrip())
  42. msg('')
  43. def do_msg(rpc,backend):
  44. bname = type(rpc.backend).__name__
  45. qmsg(' Testing backend {!r}{}'.format( bname, '' if backend == bname else f' [{backend}]' ))
  46. class init_test:
  47. async def btc(proto,backend,daemon):
  48. rpc = await rpc_init(proto,backend,daemon)
  49. do_msg(rpc,backend)
  50. bh = (await rpc.call('getblockchaininfo',timeout=300))['bestblockhash']
  51. await rpc.gathered_call('getblock',((bh,),(bh,1)),timeout=300)
  52. await rpc.gathered_call(None,(('getblock',(bh,)),('getblock',(bh,1))),timeout=300)
  53. return rpc
  54. async def bch(proto,backend,daemon):
  55. rpc = await rpc_init(proto,backend,daemon)
  56. do_msg(rpc,backend)
  57. return rpc
  58. ltc = bch
  59. async def eth(proto,backend,daemon):
  60. rpc = await rpc_init(proto,backend,daemon)
  61. do_msg(rpc,backend)
  62. await rpc.call('eth_blockNumber',timeout=300)
  63. return rpc
  64. etc = eth
  65. def run_test(network_ids,test_cf_auth=False,daemon_ids=None):
  66. def do(d):
  67. if not opt.no_daemon_stop:
  68. d.stop()
  69. if not opt.no_daemon_autostart:
  70. d.remove_datadir()
  71. d.start()
  72. for n,backend in enumerate(g.autoset_opts['rpc_backend'].choices):
  73. test = getattr(init_test,d.proto.coin.lower())
  74. rpc = run_session(test(d.proto,backend,d),backend=backend)
  75. if not n and opt.verbose:
  76. print_daemon_info(rpc)
  77. if not opt.no_daemon_stop:
  78. d.stop()
  79. if test_cf_auth and g.platform != 'win':
  80. cfg_file_auth_test(d.proto,d)
  81. qmsg('')
  82. for network_id in network_ids:
  83. proto = init_proto(network_id=network_id)
  84. ids = (lambda x:
  85. set(daemon_ids) & set(x) if daemon_ids else x
  86. )(CoinDaemon.get_daemon_ids(proto.coin))
  87. for daemon_id in ids:
  88. do( CoinDaemon(proto=proto,test_suite=True,daemon_id=daemon_id) )
  89. return True
  90. class unit_tests:
  91. altcoin_deps = ('ltc','bch','geth','erigon','openethereum','parity','xmrwallet')
  92. win_skip = ('xmrwallet',) # FIXME - wallet doesn't open
  93. arm_skip = ('openethereum','parity') # no prebuilt binaries for ARM
  94. def btc(self,name,ut):
  95. return run_test(['btc','btc_tn'],test_cf_auth=True)
  96. def ltc(self,name,ut):
  97. return run_test(['ltc','ltc_tn'],test_cf_auth=True)
  98. def bch(self,name,ut):
  99. return run_test(['bch','bch_tn'],test_cf_auth=True)
  100. def geth(self,name,ut):
  101. return run_test(['eth_tn','eth_rt'],daemon_ids=['geth']) # mainnet returns EIP-155 error on empty blockchain
  102. def erigon(self,name,ut):
  103. return run_test(['eth','eth_tn','eth_rt'],daemon_ids=['erigon'])
  104. def openethereum(self,name,ut):
  105. return run_test(['eth','eth_tn','eth_rt'],daemon_ids=['openethereum'])
  106. def parity(self,name,ut):
  107. return run_test(['etc'])
  108. def xmrwallet(self,name,ut):
  109. async def test_monerod_rpc(md):
  110. md_rpc = MoneroRPCClientRaw(
  111. host = md.host,
  112. port = md.rpc_port,
  113. user = None,
  114. passwd = None,
  115. test_connection = False,
  116. daemon = md,
  117. )
  118. md_json_rpc = MoneroRPCClient(
  119. host = md.host,
  120. port = md.rpc_port,
  121. user = None,
  122. passwd = None,
  123. test_connection = False,
  124. daemon = md,
  125. )
  126. await md_rpc.call('get_height')
  127. await md_json_rpc.call('get_last_block_header')
  128. async def run():
  129. networks = init_proto('xmr').networks
  130. daemons = [(
  131. CoinDaemon(proto=proto,test_suite=True),
  132. MoneroWalletDaemon(
  133. proto = proto,
  134. test_suite = True,
  135. wallet_dir = 'test/trash2',
  136. passwd = 'ut_rpc_passw0rd' )
  137. ) for proto in (init_proto( 'xmr', network=network ) for network in networks) ]
  138. for md,wd in daemons:
  139. if not opt.no_daemon_autostart:
  140. md.start()
  141. wd.start()
  142. await test_monerod_rpc(md)
  143. c = MoneroWalletRPCClient(daemon=wd)
  144. fn = f'monero-{wd.network}-junk-wallet'
  145. qmsg(f'Creating {wd.network} wallet')
  146. await c.call(
  147. 'restore_deterministic_wallet',
  148. filename = fn,
  149. password = 'foo',
  150. seed = xmrseed().fromhex('beadface'*8,tostr=True) )
  151. qmsg(f'Opening {wd.network} wallet')
  152. await c.call( 'open_wallet', filename=fn, password='foo' )
  153. for md,wd in daemons:
  154. wd.wait = False
  155. await wd.rpc.stop_daemon()
  156. if not opt.no_daemon_stop:
  157. md.wait = False
  158. await md.rpc.stop_daemon()
  159. gmsg('OK')
  160. from mmgen.xmrseed import xmrseed
  161. import shutil
  162. shutil.rmtree('test/trash2',ignore_errors=True)
  163. os.makedirs('test/trash2')
  164. run_session(run())
  165. return True