daemon.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. proto.btc.daemon: Bitcoin base protocol daemon classes
  12. """
  13. import os
  14. from ...globalvars import g
  15. from ...util import list_gen
  16. from ...daemon import CoinDaemon,_nw,_dd
  17. class bitcoin_core_daemon(CoinDaemon):
  18. daemon_data = _dd('Bitcoin Core', 230000, '23.0.0')
  19. exec_fn = 'bitcoind'
  20. cli_fn = 'bitcoin-cli'
  21. testnet_dir = 'testnet3'
  22. cfg_file_hdr = '# Bitcoin Core config file\n'
  23. tracking_wallet_name = 'mmgen-tracking-wallet'
  24. rpc_ports = _nw(8332, 18332, 18443)
  25. cfg_file = 'bitcoin.conf'
  26. datadirs = {
  27. 'linux': [g.home_dir,'.bitcoin'],
  28. 'win': [os.getenv('APPDATA'),'Bitcoin']
  29. }
  30. nonstd_datadir = False
  31. def init_datadir(self):
  32. if self.network == 'regtest' and not self.test_suite:
  33. return os.path.join( g.data_dir_root, 'regtest', g.coin.lower() )
  34. else:
  35. return super().init_datadir()
  36. @property
  37. def network_datadir(self):
  38. "location of the network's blockchain data and authentication cookie"
  39. return os.path.join (
  40. self.datadir, {
  41. 'mainnet': '',
  42. 'testnet': self.testnet_dir,
  43. 'regtest': 'regtest',
  44. }[self.network] )
  45. def init_subclass(self):
  46. if self.network == 'regtest':
  47. """
  48. fall back on hard-coded credentials
  49. """
  50. from .regtest import MMGenRegtest
  51. self.rpc_user = MMGenRegtest.rpc_user
  52. self.rpc_password = MMGenRegtest.rpc_password
  53. self.shared_args = list_gen(
  54. [f'--datadir={self.datadir}', self.nonstd_datadir or self.non_dfl_datadir],
  55. [f'--rpcport={self.rpc_port}'],
  56. [f'--rpcuser={self.rpc_user}', self.network == 'regtest'],
  57. [f'--rpcpassword={self.rpc_password}', self.network == 'regtest'],
  58. ['--testnet', self.network == 'testnet'],
  59. ['--regtest', self.network == 'regtest'],
  60. )
  61. self.coind_args = list_gen(
  62. ['--listen=0'],
  63. ['--keypool=1'],
  64. ['--rpcallowip=127.0.0.1'],
  65. [f'--rpcbind=127.0.0.1:{self.rpc_port}'],
  66. ['--pid='+self.pidfile, self.use_pidfile],
  67. ['--daemon', self.platform == 'linux' and not self.opt.no_daemonize],
  68. ['--fallbackfee=0.0002', self.coin == 'BTC' and self.network == 'regtest'],
  69. ['--usecashaddr=0', self.coin == 'BCH'],
  70. ['--mempoolreplacement=1', self.coin == 'LTC'],
  71. ['--txindex=1', self.coin == 'LTC' or self.network == 'regtest'],
  72. ['--addresstype=bech32', self.coin == 'LTC' and self.network == 'regtest'],
  73. )
  74. self.lockfile = os.path.join(self.network_datadir,'.cookie')
  75. @property
  76. def state(self):
  77. cp = self.cli('getblockcount',silent=True)
  78. err = cp.stderr.decode()
  79. if ("error: couldn't connect" in err
  80. or "error: Could not connect" in err
  81. or "does not exist" in err ):
  82. # regtest has no cookie file, so test will always fail
  83. ret = 'busy' if (self.lockfile and os.path.exists(self.lockfile)) else 'stopped'
  84. elif cp.returncode == 0:
  85. ret = 'ready'
  86. else:
  87. ret = 'busy'
  88. if self.debug:
  89. print(f'State: {ret!r}')
  90. return ret
  91. @property
  92. def stop_cmd(self):
  93. return self.cli_cmd('stop')
  94. def set_label_args(self,rpc,coinaddr,lbl):
  95. if 'label_api' in rpc.caps:
  96. return ('setlabel',coinaddr,lbl)
  97. else:
  98. # NOTE: this works because importaddress() removes the old account before
  99. # associating the new account with the address.
  100. # RPC args: addr,label,rescan[=true],p2sh[=none]
  101. return ('importaddress',coinaddr,lbl,False)
  102. def estimatefee_args(self,rpc):
  103. return (opt.tx_confs,)
  104. def sigfail_errmsg(self,e):
  105. return e.args[0]
  106. class bitcoin_cash_node_daemon(bitcoin_core_daemon):
  107. daemon_data = _dd('Bitcoin Cash Node', 24010000, '24.1.0')
  108. exec_fn = 'bitcoind-bchn'
  109. cli_fn = 'bitcoin-cli-bchn'
  110. rpc_ports = _nw(8432, 18432, 18543) # use non-standard ports (core+100)
  111. datadirs = {
  112. 'linux': [g.home_dir,'.bitcoin-bchn'],
  113. 'win': [os.getenv('APPDATA'),'Bitcoin_ABC']
  114. }
  115. cfg_file_hdr = '# Bitcoin Cash Node config file\n'
  116. nonstd_datadir = True
  117. def set_label_args(self,rpc,coinaddr,lbl):
  118. # bitcoin-{abc,bchn} 'setlabel' RPC is broken, so use old 'importaddress' method to set label
  119. # Broken behavior: new label is set OK, but old label gets attached to another address
  120. return ('importaddress',coinaddr,lbl,False)
  121. def estimatefee_args(self,rpc):
  122. return () if rpc.daemon_version >= 190100 else (opt.tx_confs,)
  123. def sigfail_errmsg(self,e):
  124. return (
  125. 'This is not the BCH chain.\nRe-run the script without the --coin=bch option.'
  126. if 'Invalid sighash param' in e.args[0] else
  127. e.args[0] )
  128. class litecoin_core_daemon(bitcoin_core_daemon):
  129. # v0.21.2rc5 crashes when mining more than 431 blocks in regtest mode:
  130. # CreateNewBlock: TestBlockValidity failed: bad-txns-vin-empty, Transaction check failed
  131. daemon_data = _dd('Litecoin Core', 210201, '0.21.2.1')
  132. exec_fn = 'litecoind'
  133. cli_fn = 'litecoin-cli'
  134. testnet_dir = 'testnet4'
  135. rpc_ports = _nw(9332, 19332, 19443)
  136. cfg_file = 'litecoin.conf'
  137. datadirs = {
  138. 'linux': [g.home_dir,'.litecoin'],
  139. 'win': [os.getenv('APPDATA'),'Litecoin']
  140. }
  141. cfg_file_hdr = '# Litecoin Core config file\n'