- Bitcoin Core v31.0.0 - Litecoin Core v0.21.5.4 - Bitcoin Cash Node v29.0.0 - Go-Ethereum v1.17.2
216 lines
7.1 KiB
Python
Executable file
216 lines
7.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
#
|
|
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
|
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
|
# Licensed under the GNU General Public License, Version 3:
|
|
# https://www.gnu.org/licenses
|
|
# Public project repositories:
|
|
# https://github.com/mmgen/mmgen-wallet
|
|
# https://gitlab.com/mmgen/mmgen-wallet
|
|
|
|
"""
|
|
proto.eth.daemon: Ethereum base protocol daemon classes
|
|
"""
|
|
|
|
import os
|
|
|
|
from ...cfg import gc
|
|
from ...util import list_gen, get_subclasses
|
|
from ...daemon import CoinDaemon, RPCDaemon, _nw, _dd
|
|
|
|
class ethereum_daemon(CoinDaemon):
|
|
chain_subdirs = _nw('ethereum', 'goerli', 'DevelopmentChain')
|
|
base_rpc_port = 8545 # same for all networks!
|
|
base_authrpc_port = 8551 # same for all networks!
|
|
base_p2p_port = 30303 # same for all networks!
|
|
daemon_port_offset = 100
|
|
network_port_offsets = _nw(0, 10, 20)
|
|
|
|
def __init__(self, *args, test_suite=False, **kwargs):
|
|
|
|
if not hasattr(self, 'all_daemons'):
|
|
ethereum_daemon.all_daemons = get_subclasses(ethereum_daemon, names=True)
|
|
|
|
daemon_idx_offset = (
|
|
self.all_daemons.index(self.id+'_daemon') * self.daemon_port_offset
|
|
if test_suite else 0)
|
|
|
|
self.port_offset = daemon_idx_offset + getattr(self.network_port_offsets, self.network)
|
|
|
|
super().__init__(*args, test_suite=test_suite, **kwargs)
|
|
|
|
def get_rpc_port(self):
|
|
return self.base_rpc_port + self.port_offset
|
|
|
|
@property
|
|
def authrpc_port(self):
|
|
return self.base_authrpc_port + self.port_offset
|
|
|
|
def get_p2p_port(self):
|
|
return self.base_p2p_port + self.port_offset
|
|
|
|
def init_datadir(self):
|
|
self.logdir = super().init_datadir()
|
|
return os.path.join(
|
|
self.logdir,
|
|
self.id,
|
|
getattr(self.chain_subdirs, self.network))
|
|
|
|
class openethereum_daemon(ethereum_daemon):
|
|
daemon_data = _dd('OpenEthereum', 3003005, '3.3.5')
|
|
version_pat = r'OpenEthereum//v(\d+)\.(\d+)\.(\d+)'
|
|
exec_fn = 'openethereum'
|
|
cfg_file = 'parity.conf'
|
|
datadirs = {
|
|
'linux': [gc.home_dir, '.local', 'share', 'io.parity.ethereum'],
|
|
'darwin': [gc.home_dir, 'Library', 'Application Support', 'io.parity.ethereum'],
|
|
'win32': [os.getenv('LOCALAPPDATA'), 'Parity', 'Ethereum']}
|
|
|
|
def init_subclass(self):
|
|
|
|
self.use_pidfile = self.platform == 'linux' and not self.opt.no_daemonize
|
|
self.use_threads = self.platform in ('win32', 'darwin')
|
|
|
|
self.coind_args = list_gen(
|
|
['--no-ws'],
|
|
['--no-ipc'],
|
|
['--no-secretstore'],
|
|
[f'--jsonrpc-port={self.rpc_port}'],
|
|
[f'--port={self.p2p_port}', self.p2p_port],
|
|
[f'--base-path={self.datadir}', self.non_dfl_datadir],
|
|
[f'--chain={self.proto.chain_name}', self.network!='regtest'],
|
|
['--config=dev', self.network=='regtest'], # no presets for mainnet or testnet
|
|
['--mode=offline', self.test_suite or self.network=='regtest'],
|
|
[f'--log-file={self.logfile}', self.non_dfl_datadir],
|
|
['daemon', self.use_pidfile],
|
|
[self.pidfile, self.use_pidfile],
|
|
)
|
|
|
|
class parity_daemon(openethereum_daemon):
|
|
daemon_data = _dd('Parity', 2007002, '2.7.2')
|
|
version_pat = r'Parity-Ethereum//v(\d+)\.(\d+)\.(\d+)'
|
|
exec_fn = 'parity'
|
|
|
|
class geth_daemon(ethereum_daemon):
|
|
# v1.14.0 -> ? (v1.15.11 and later OK)
|
|
# mempool deadlock in dev mode: "transaction indexing is in progress"
|
|
# https://github.com/ethereum/go-ethereum/issues/29475
|
|
# offending commit (via git bisect): 0a2f33946b95989e8ce36e72a88138adceab6a23
|
|
daemon_data = _dd('Geth', 1017002, '1.17.2')
|
|
version_pat = r'Geth/v(\d+)\.(\d+)\.(\d+)'
|
|
exec_fn = 'geth'
|
|
use_pidfile = False
|
|
use_threads = True
|
|
avail_opts = ('no_daemonize', 'online')
|
|
version_info_arg = 'version'
|
|
datadirs = {
|
|
'linux': [gc.home_dir, '.ethereum', 'geth'],
|
|
'darwin': [gc.home_dir, 'Library', 'Ethereum', 'geth'],
|
|
'win32': [os.getenv('LOCALAPPDATA'), 'Geth']} # FIXME
|
|
|
|
def init_subclass(self):
|
|
|
|
self.coind_args = list_gen(
|
|
['node', self.id == 'reth'],
|
|
['--quiet', self.id == 'reth'],
|
|
['--disable-dns-discovery', self.id == 'reth' and self.test_suite],
|
|
['--verbosity=0', self.id == 'geth'],
|
|
['--ipcdisable'], # IPC-RPC: if path to socket is longer than 108 chars, geth fails to start
|
|
['--http'],
|
|
['--http.api=eth,web3,txpool'],
|
|
[f'--http.port={self.rpc_port}'],
|
|
[f'--authrpc.port={self.authrpc_port}'],
|
|
[f'--port={self.p2p_port}', self.p2p_port], # geth binds p2p port even with --maxpeers=0
|
|
[f'--discovery.port={self.p2p_port}', self.id == 'reth' and self.p2p_port],
|
|
['--maxpeers=0', self.id == 'geth' and not self.opt.online],
|
|
[f'--datadir={self.datadir}', self.non_dfl_datadir],
|
|
['--holesky', self.network=='testnet' and self.id == 'geth'],
|
|
['--chain=holesky', self.network=='testnet' and self.id == 'reth'],
|
|
['--dev', self.network=='regtest'],
|
|
)
|
|
|
|
class reth_daemon(geth_daemon):
|
|
daemon_data = _dd('Reth', 2001000, '2.1.0')
|
|
version_pat = r'reth/v(\d+)\.(\d+)\.(\d+)'
|
|
exec_fn = 'reth'
|
|
version_info_arg = '--version'
|
|
datadirs = {
|
|
'linux': [gc.home_dir, '.local', 'share', 'reth']}
|
|
|
|
# https://github.com/ledgerwatch/erigon
|
|
class erigon_daemon(geth_daemon):
|
|
daemon_data = _dd('Erigon', 2022099099, '2022.99.99')
|
|
version_pat = r'erigon/(\d+)\.(\d+)\.(\d+)'
|
|
exec_fn = 'erigon'
|
|
private_ports = _nw(9090, 9091, 9092) # testnet and regtest are non-standard
|
|
torrent_ports = _nw(42069, 42070, None) # testnet is non-standard
|
|
version_info_arg = '--version'
|
|
datadirs = {
|
|
'linux': [gc.home_dir, '.local', 'share', 'erigon'],
|
|
'win32': [os.getenv('LOCALAPPDATA'), 'Erigon']} # FIXME
|
|
|
|
def init_subclass(self):
|
|
|
|
if self.network == 'regtest':
|
|
self.force_kill = True
|
|
|
|
self.coind_args = list_gen(
|
|
['--verbosity=0'],
|
|
[f'--port={self.p2p_port}', self.p2p_port],
|
|
['--maxpeers=0', not self.opt.online],
|
|
[f'--private.api.addr=127.0.0.1:{self.private_port}'],
|
|
[f'--datadir={self.datadir}', self.non_dfl_datadir],
|
|
['--chain=goerli', self.network=='testnet'],
|
|
[f'--torrent.port={self.torrent_ports.testnet}', self.network=='testnet'],
|
|
['--chain=dev', self.network=='regtest'],
|
|
['--mine', self.network=='regtest'],
|
|
)
|
|
|
|
self.rpc_d = erigon_rpcdaemon(
|
|
cfg = self.cfg,
|
|
proto = self.proto,
|
|
rpc_port = self.rpc_port,
|
|
private_port = self.private_port,
|
|
test_suite = self.test_suite,
|
|
datadir = self.datadir)
|
|
|
|
def start(self, *, quiet=False, silent=False):
|
|
super().start(quiet=quiet, silent=silent)
|
|
self.rpc_d.debug = self.debug
|
|
return self.rpc_d.start(quiet=quiet, silent=silent)
|
|
|
|
def stop(self, *, quiet=False, silent=False):
|
|
self.rpc_d.debug = self.debug
|
|
self.rpc_d.stop(quiet=quiet, silent=silent)
|
|
return super().stop(quiet=quiet, silent=silent)
|
|
|
|
@property
|
|
def start_cmds(self):
|
|
return [self.start_cmd, self.rpc_d.start_cmd]
|
|
|
|
class erigon_rpcdaemon(RPCDaemon):
|
|
|
|
master_daemon = 'erigon_daemon'
|
|
rpc_desc = 'Erigon'
|
|
exec_fn = 'rpcdaemon'
|
|
use_pidfile = False
|
|
use_threads = True
|
|
|
|
def __init__(self, cfg, proto, *, rpc_port, private_port, test_suite, datadir):
|
|
|
|
self.proto = proto
|
|
self.test_suite = test_suite
|
|
|
|
super().__init__(cfg)
|
|
|
|
self.network = proto.network
|
|
self.rpc_port = rpc_port
|
|
self.datadir = datadir
|
|
|
|
self.daemon_args = list_gen(
|
|
['--verbosity=0'],
|
|
[f'--private.api.addr=127.0.0.1:{private_port}'],
|
|
[f'--http.port={self.rpc_port}'],
|
|
[f'--datadir={self.datadir}'],
|
|
['--http.api=eth,erigon,web3,net,debug,trace,txpool,parity'],
|
|
)
|