daemon.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
  4. # Copyright (C)2013-2022 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
  9. # https://gitlab.com/mmgen/mmgen
  10. """
  11. base_proto.ethereum.daemon: Ethereum base protocol daemon classes
  12. """
  13. import os
  14. from ...globalvars import g
  15. from ...util import list_gen,get_subclasses
  16. from ...daemon import CoinDaemon,RPCDaemon,_nw,_dd
  17. class ethereum_daemon(CoinDaemon):
  18. chain_subdirs = _nw('ethereum','goerli','DevelopmentChain')
  19. base_rpc_port = 8545 # same for all networks!
  20. base_p2p_port = 30303 # same for all networks!
  21. daemon_port_offset = 100
  22. network_port_offsets = _nw(0,10,20)
  23. def __init__(self,*args,**kwargs):
  24. if not hasattr(self,'all_daemons'):
  25. ethereum_daemon.all_daemons = get_subclasses(ethereum_daemon,names=True)
  26. self.port_offset = (
  27. self.all_daemons.index(self.id+'_daemon') * self.daemon_port_offset
  28. + getattr(self.network_port_offsets,self.network) )
  29. return super().__init__(*args,**kwargs)
  30. def get_rpc_port(self):
  31. return self.base_rpc_port + self.port_offset
  32. def get_p2p_port(self):
  33. return self.base_p2p_port + self.port_offset
  34. def init_datadir(self):
  35. self.logdir = super().init_datadir()
  36. return os.path.join(
  37. self.logdir,
  38. self.id,
  39. getattr(self.chain_subdirs,self.network) )
  40. class openethereum_daemon(ethereum_daemon):
  41. daemon_data = _dd('OpenEthereum', 3003005, '3.3.5')
  42. version_pat = r'OpenEthereum//v(\d+)\.(\d+)\.(\d+)'
  43. exec_fn = 'openethereum'
  44. cfg_file = 'parity.conf'
  45. datadirs = {
  46. 'linux': [g.home_dir,'.local','share','io.parity.ethereum'],
  47. 'win': [os.getenv('LOCALAPPDATA'),'Parity','Ethereum']
  48. }
  49. def init_subclass(self):
  50. ld = self.platform == 'linux' and not self.opt.no_daemonize
  51. self.coind_args = list_gen(
  52. ['--no-ws'],
  53. ['--no-ipc'],
  54. ['--no-secretstore'],
  55. [f'--jsonrpc-port={self.rpc_port}'],
  56. [f'--port={self.p2p_port}', self.p2p_port],
  57. [f'--base-path={self.datadir}', self.non_dfl_datadir],
  58. [f'--chain={self.proto.chain_name}', self.network!='regtest'],
  59. [f'--config=dev', self.network=='regtest'], # no presets for mainnet or testnet
  60. ['--mode=offline', self.test_suite or self.network=='regtest'],
  61. [f'--log-file={self.logfile}', self.non_dfl_datadir],
  62. ['daemon', ld],
  63. [self.pidfile, ld],
  64. )
  65. class parity_daemon(openethereum_daemon):
  66. daemon_data = _dd('Parity', 2007002, '2.7.2')
  67. version_pat = r'Parity-Ethereum//v(\d+)\.(\d+)\.(\d+)'
  68. exec_fn = 'parity'
  69. class geth_daemon(ethereum_daemon):
  70. # bug in v1.10.17 requires --dev to be omitted to initialize blockchain (devnet_init_bug)
  71. # daemon_data = _dd('Geth', 1010017, '1.10.17')
  72. daemon_data = _dd('Geth', 1010014, '1.10.14')
  73. version_pat = r'Geth/v(\d+)\.(\d+)\.(\d+)'
  74. exec_fn = 'geth'
  75. use_pidfile = False
  76. use_threads = True
  77. datadirs = {
  78. 'linux': [g.home_dir,'.ethereum','geth'],
  79. 'win': [os.getenv('LOCALAPPDATA'),'Geth'] # FIXME
  80. }
  81. avail_opts = ('no_daemonize','online','devnet_init_bug')
  82. def init_subclass(self):
  83. self.coind_args = list_gen(
  84. ['--verbosity=0'],
  85. ['--http'],
  86. ['--http.api=eth,web3,txpool'],
  87. [f'--http.port={self.rpc_port}'],
  88. [f'--port={self.p2p_port}', self.p2p_port], # geth binds p2p port even with --maxpeers=0
  89. ['--maxpeers=0', not self.opt.online],
  90. [f'--datadir={self.datadir}', self.non_dfl_datadir],
  91. ['--goerli', self.network=='testnet'],
  92. ['--dev', self.network=='regtest' and not self.opt.devnet_init_bug],
  93. )
  94. # https://github.com/ledgerwatch/erigon
  95. class erigon_daemon(geth_daemon):
  96. daemon_data = _dd('Erigon', 2022099099, '2022.99.99')
  97. version_pat = r'erigon/(\d+)\.(\d+)\.(\d+)'
  98. exec_fn = 'erigon'
  99. private_ports = _nw(9090,9091,9092) # testnet and regtest are non-standard
  100. datadirs = {
  101. 'linux': [g.home_dir,'.local','share','erigon'],
  102. 'win': [os.getenv('LOCALAPPDATA'),'Erigon'] # FIXME
  103. }
  104. def init_subclass(self):
  105. self.coind_args = list_gen(
  106. ['--verbosity=0'],
  107. [f'--port={self.p2p_port}', self.p2p_port],
  108. ['--maxpeers=0', not self.opt.online],
  109. [f'--private.api.addr=127.0.0.1:{self.private_port}'],
  110. [f'--datadir={self.datadir}', self.non_dfl_datadir],
  111. ['--chain=goerli', self.network=='testnet'],
  112. ['--chain=dev', self.network=='regtest'],
  113. ['--mine', self.network=='regtest'],
  114. )
  115. self.rpc_d = erigon_rpcdaemon(
  116. proto = self.proto,
  117. rpc_port = self.rpc_port,
  118. private_port = self.private_port,
  119. test_suite = self.test_suite,
  120. datadir = self.datadir )
  121. def start(self,quiet=False,silent=False):
  122. super().start(quiet=quiet,silent=silent)
  123. self.rpc_d.debug = self.debug
  124. return self.rpc_d.start(quiet=quiet,silent=silent)
  125. def stop(self,quiet=False,silent=False):
  126. self.rpc_d.debug = self.debug
  127. self.rpc_d.stop(quiet=quiet,silent=silent)
  128. return super().stop(quiet=quiet,silent=silent)
  129. @property
  130. def start_cmds(self):
  131. return [self.start_cmd,self.rpc_d.start_cmd]
  132. class erigon_rpcdaemon(RPCDaemon):
  133. master_daemon = 'erigon_daemon'
  134. rpc_type = 'Erigon'
  135. exec_fn = 'rpcdaemon'
  136. use_pidfile = False
  137. use_threads = True
  138. def __init__(self,proto,rpc_port,private_port,test_suite,datadir):
  139. self.proto = proto
  140. self.test_suite = test_suite
  141. super().__init__()
  142. self.network = proto.network
  143. self.rpc_port = rpc_port
  144. self.datadir = datadir
  145. self.daemon_args = list_gen(
  146. ['--verbosity=0'],
  147. [f'--private.api.addr=127.0.0.1:{private_port}'],
  148. [f'--http.port={self.rpc_port}'],
  149. [f'--datadir={self.datadir}'],
  150. ['--http.api=eth,erigon,web3,net,debug,trace,txpool,parity'],
  151. )