daemon.py,rpc.py: cleanups and fixes
This commit is contained in:
parent
59c96fb16b
commit
305f986698
4 changed files with 53 additions and 112 deletions
108
mmgen/daemon.py
108
mmgen/daemon.py
|
|
@ -27,7 +27,8 @@ from .exception import *
|
|||
from .common import *
|
||||
|
||||
_dd = namedtuple('daemon_data',['coind_name','coind_version','coind_version_str']) # latest tested version
|
||||
_pd = namedtuple('rpc_ports_data',['mainnet','testnet','regtest'])
|
||||
_cd = namedtuple('coins_data',['coin_name','daemon_ids'])
|
||||
_nw = namedtuple('coin_networks',['mainnet','testnet','regtest'])
|
||||
|
||||
class Daemon(MMGenObject):
|
||||
|
||||
|
|
@ -106,6 +107,13 @@ class Daemon(MMGenObject):
|
|||
else:
|
||||
return '(unknown)'
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return 'ready' if self.test_socket('localhost',self.rpc_port) else 'stopped'
|
||||
|
||||
@property
|
||||
def stop_cmd(self):
|
||||
return ['kill','-Wf',self.pid] if self.platform == 'win' else ['kill',self.pid]
|
||||
|
||||
def cmd(self,action,*args,**kwargs):
|
||||
return getattr(self,action)(*args,**kwargs)
|
||||
|
|
@ -186,13 +194,6 @@ class Daemon(MMGenObject):
|
|||
m = 'Wait for state {!r} timeout exceeded for daemon {} {} (port {})'
|
||||
die(2,m.format(req_state,self.coin,self.network,self.rpc_port))
|
||||
|
||||
@classmethod
|
||||
def check_implement(cls):
|
||||
m = 'required method {}() missing in class {}'
|
||||
for subcls in cls.__subclasses__():
|
||||
for k in cls.subclasses_must_implement:
|
||||
assert k in subcls.__dict__, m.format(k,subcls.__name__)
|
||||
|
||||
@property
|
||||
def flags(self):
|
||||
return self._flags
|
||||
|
|
@ -295,37 +296,14 @@ class MoneroWalletDaemon(Daemon):
|
|||
def start_cmd(self):
|
||||
return (['monero-wallet-rpc'] + self.daemon_args + self.usr_daemon_args )
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return 'ready' if self.test_socket('localhost',self.rpc_port) else 'stopped'
|
||||
# TBD:
|
||||
if not self.test_socket(self.host,self.rpc_port):
|
||||
return 'stopped'
|
||||
from .rpc import MoneroWalletRPCClient
|
||||
try:
|
||||
MoneroWalletRPCClient(
|
||||
self.host,
|
||||
self.rpc_port,
|
||||
self.user,
|
||||
self.passwd).call('get_version')
|
||||
return 'ready'
|
||||
except:
|
||||
return 'stopped'
|
||||
|
||||
@property
|
||||
def stop_cmd(self):
|
||||
return ['kill','-Wf',self.pid] if self.platform == 'win' else ['kill',self.pid]
|
||||
|
||||
class CoinDaemon(Daemon):
|
||||
networks = ('mainnet','testnet','regtest')
|
||||
cfg_file_hdr = ''
|
||||
subclasses_must_implement = ('state','stop_cmd')
|
||||
avail_flags = ('keep_cfg_file',)
|
||||
avail_opts = ('no_daemonize','online')
|
||||
datadir_is_subdir = False
|
||||
data_subdir = ''
|
||||
|
||||
_cd = namedtuple('coins_data',['coin_name','daemon_ids'])
|
||||
coins = {
|
||||
'BTC': _cd('Bitcoin', ['bitcoin_core']),
|
||||
'BCH': _cd('Bitcoin Cash Node', ['bitcoin_cash_node']),
|
||||
|
|
@ -470,7 +448,7 @@ class bitcoin_core_daemon(CoinDaemon):
|
|||
testnet_dir = 'testnet3'
|
||||
cfg_file_hdr = '# BitcoinCoreDaemon config file\n'
|
||||
tracking_wallet_name = 'mmgen-tracking-wallet'
|
||||
rpc_ports = _pd(8332, 18332, 18444)
|
||||
rpc_ports = _nw(8332, 18332, 18444)
|
||||
cfg_file = 'bitcoin.conf'
|
||||
datadirs = {
|
||||
'linux': [g.home_dir,'.bitcoin'],
|
||||
|
|
@ -535,7 +513,7 @@ class bitcoin_cash_node_daemon(bitcoin_core_daemon):
|
|||
daemon_data = _dd('Bitcoin Cash Node', 23000000, '23.0.0')
|
||||
exec_fn = 'bitcoind-bchn'
|
||||
cli_fn = 'bitcoin-cli-bchn'
|
||||
rpc_ports = _pd(8442, 18442, 18553) # use non-standard ports
|
||||
rpc_ports = _nw(8442, 18442, 18553) # use non-standard ports
|
||||
datadirs = {
|
||||
'linux': [g.home_dir,'.bitcoin-bchn'],
|
||||
'win': [os.getenv('APPDATA'),'Bitcoin_ABC']
|
||||
|
|
@ -546,7 +524,7 @@ class litecoin_core_daemon(bitcoin_core_daemon):
|
|||
exec_fn = 'litecoind'
|
||||
cli_fn = 'litecoin-cli'
|
||||
testnet_dir = 'testnet4'
|
||||
rpc_ports = _pd(9332, 19332, 19444)
|
||||
rpc_ports = _nw(9332, 19332, 19444)
|
||||
cfg_file = 'litecoin.conf'
|
||||
datadirs = {
|
||||
'linux': [g.home_dir,'.litecoin'],
|
||||
|
|
@ -561,7 +539,7 @@ class monero_daemon(CoinDaemon):
|
|||
ps_pid_mswin = True
|
||||
new_console_mswin = True
|
||||
host = 'localhost' # FIXME
|
||||
rpc_ports = _pd(18081, 38081, None)
|
||||
rpc_ports = _nw(18081, 38081, None)
|
||||
cfg_file = 'bitmonero.conf'
|
||||
datadir_is_subdir = True
|
||||
datadirs = {
|
||||
|
|
@ -595,49 +573,30 @@ class monero_daemon(CoinDaemon):
|
|||
['--offline', not 'online' in self.opts],
|
||||
)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return 'ready' if self.test_socket(self.host,self.rpc_port) else 'stopped'
|
||||
# TODO:
|
||||
if not self.test_socket(self.host,self.rpc_port):
|
||||
return 'stopped'
|
||||
cp = self.run_cmd(
|
||||
[self.exec_fn]
|
||||
+ self.shared_args
|
||||
+ ['status'],
|
||||
silent=True,
|
||||
check=False )
|
||||
return 'stopped' if 'Error:' in cp.stdout.decode() else 'ready'
|
||||
|
||||
@property
|
||||
def stop_cmd(self):
|
||||
if self.platform == 'win':
|
||||
return ['kill','-Wf',self.pid]
|
||||
else:
|
||||
return [self.exec_fn] + self.shared_args + ['exit']
|
||||
return ['kill','-Wf',self.pid] if self.platform == 'win' else [self.exec_fn] + self.shared_args + ['exit']
|
||||
|
||||
class openethereum_daemon(CoinDaemon):
|
||||
daemon_data = _dd('OpenEthereum', 3003000, '3.3.0')
|
||||
chain_subdirs = _nw('ethereum','goerli','DevelopmentChain')
|
||||
version_pat = r'OpenEthereum//v(\d+)\.(\d+)\.(\d+)'
|
||||
exec_fn = 'openethereum'
|
||||
ps_pid_mswin = True
|
||||
ports_shift = { 'mainnet': 0, 'testnet': 20, 'regtest': 40 }
|
||||
rpc_ports = _pd(*[8545 + n for n in ports_shift.values()]) # testnet and regtest are non-standard
|
||||
ports_shift = _nw(0,20,40)
|
||||
rpc_ports = _nw(*[8545 + n for n in ports_shift]) # testnet and regtest are non-standard
|
||||
cfg_file = 'parity.conf'
|
||||
datadirs = {
|
||||
'linux': [g.home_dir,'.local','share','io.parity.ethereum'],
|
||||
'win': [g.home_dir,'.local','share','io.parity.ethereum'] # FIXME
|
||||
'win': [os.getenv('LOCALAPPDATA'),'Parity','Ethereum']
|
||||
}
|
||||
testnet_dir = 'testnet' # FIXME
|
||||
testnet_dir = None
|
||||
|
||||
def subclass_init(self):
|
||||
# defaults:
|
||||
# linux: $HOME/.local/share/io.parity.ethereum/chains/DevelopmentChain
|
||||
# win: $LOCALAPPDATA/Parity/Ethereum/chains/DevelopmentChain
|
||||
|
||||
base_path = os.path.join(self.datadir,self.proto.chain_name)
|
||||
base_path = os.path.join(self.datadir,'chains',getattr(self.chain_subdirs,self.network))
|
||||
shutil.rmtree(base_path,ignore_errors=True)
|
||||
|
||||
ps = self.port_shift + self.ports_shift[self.network]
|
||||
ps = self.port_shift + getattr(self.ports_shift,self.network)
|
||||
ld = self.platform == 'linux' and not 'no_daemonize' in self.opts
|
||||
|
||||
self.coind_args = list_gen(
|
||||
|
|
@ -653,26 +612,3 @@ class openethereum_daemon(CoinDaemon):
|
|||
['daemon', ld],
|
||||
[self.pidfile, ld],
|
||||
)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return 'ready' if self.test_socket('localhost',self.rpc_port) else 'stopped'
|
||||
|
||||
# the following code does not work
|
||||
async def do():
|
||||
ret = await self.rpc.call('eth_chainId')
|
||||
return ('stopped','ready')[ret == '0x11']
|
||||
|
||||
try:
|
||||
return run_session(do()) # socket exception is not propagated
|
||||
except:# SocketError:
|
||||
return 'stopped'
|
||||
|
||||
@property
|
||||
def stop_cmd(self):
|
||||
return ['kill','-Wf',self.pid] if self.platform == 'win' else ['kill',self.pid]
|
||||
|
||||
# class openethereum_etc_daemon(openethereum_daemon):
|
||||
# rpc_ports = _pd(*[8645 + n for n in openethereum_daemon.ports_shift.values()])
|
||||
|
||||
CoinDaemon.check_implement()
|
||||
|
|
|
|||
|
|
@ -102,8 +102,11 @@ class CoinProtocol(MMGenObject):
|
|||
'regtest': '_rt',
|
||||
}[network]
|
||||
|
||||
# first chain name is default
|
||||
self.chain_name = self.chain_names[0] if hasattr(self,'chain_names') else self.network
|
||||
if hasattr(self,'chain_names'):
|
||||
self.chain_name = self.chain_names[0] # first chain name is default
|
||||
else:
|
||||
self.chain_name = self.network
|
||||
self.chain_names = [self.network]
|
||||
|
||||
if self.tokensym:
|
||||
assert isinstance(self,CoinProtocol.Ethereum), 'CoinProtocol.Base_chk1'
|
||||
|
|
@ -124,7 +127,7 @@ class CoinProtocol(MMGenObject):
|
|||
"""
|
||||
for network in ('mainnet','testnet','regtest'):
|
||||
proto = init_proto(coin,network=network)
|
||||
for proto_chain_name in ( getattr(proto,'chain_names',None) or [network] ):
|
||||
for proto_chain_name in proto.chain_names:
|
||||
if chain_name == proto_chain_name:
|
||||
return network
|
||||
raise ValueError(f'{chain_name}: unrecognized chain name for coin {coin}')
|
||||
|
|
|
|||
47
mmgen/rpc.py
47
mmgen/rpc.py
|
|
@ -598,28 +598,32 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
|
||||
self.set_backend(backend)
|
||||
|
||||
self.blockcount = int(await self.call('eth_blockNumber'),16)
|
||||
|
||||
vi,bh,ch,nk = await self.gathered_call(None, (
|
||||
vi,bh,ci = await self.gathered_call(None, (
|
||||
('web3_clientVersion',()),
|
||||
('parity_getBlockHeaderByNumber',()),
|
||||
('parity_chain',()),
|
||||
('parity_nodeKind',()),
|
||||
('eth_getBlockByNumber',('latest',False)),
|
||||
('eth_chainId',()),
|
||||
))
|
||||
|
||||
import re
|
||||
vip = re.match(r'OpenEthereum//v(\d+)\.(\d+)\.(\d+)',vi,re.ASCII)
|
||||
vip = re.match(self.daemon.version_pat,vi,re.ASCII)
|
||||
if not vip:
|
||||
ydie(1,fmt(f"""
|
||||
Aborting on daemon mismatch:
|
||||
Requested daemon: {self.daemon.id}
|
||||
Running daemon: {vi}
|
||||
""",strip_char='\t').rstrip())
|
||||
self.daemon_version = int('{:d}{:03d}{:03d}'.format(*[int(e) for e in vip.groups()]))
|
||||
self.daemon_version_str = '{}.{}.{}'.format(*vip.groups())
|
||||
self.cur_date = int(bh['timestamp'],16)
|
||||
self.chain = ch.replace(' ','_')
|
||||
self.caps = ('full_node',) if nk['capability'] == 'full' else ()
|
||||
|
||||
try:
|
||||
await self.call('eth_chainId')
|
||||
self.caps += ('eth_chainId',)
|
||||
except RPCFailure:
|
||||
pass
|
||||
self.blockcount = int(bh['number'],16)
|
||||
self.cur_date = int(bh['timestamp'],16)
|
||||
|
||||
self.caps = ()
|
||||
if self.daemon.id == 'openethereum':
|
||||
if (await self.call('parity_nodeKind'))['capability'] == 'full':
|
||||
self.caps += ('full_node',)
|
||||
self.chainID = None
|
||||
self.chain = (await self.call('parity_chain')).replace(' ','_')
|
||||
|
||||
rpcmethods = (
|
||||
'eth_accounts',
|
||||
|
|
@ -642,7 +646,6 @@ class EthereumRPCClient(RPCClient,metaclass=aInitMeta):
|
|||
'net_peerCount',
|
||||
'net_version',
|
||||
'parity_chain',
|
||||
'parity_chainId', # superseded by eth_chainId
|
||||
'parity_getBlockHeaderByNumber',
|
||||
'parity_nextNonce',
|
||||
'parity_nodeKind',
|
||||
|
|
@ -755,12 +758,12 @@ async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False):
|
|||
if rpc.daemon_version > rpc.daemon.coind_version:
|
||||
handle_unsupported_daemon_version(rpc,proto,ignore_daemon_version)
|
||||
|
||||
if proto.chain_name != rpc.chain:
|
||||
raise RPCChainMismatch(
|
||||
'{} protocol chain is {}, but coin daemon chain is {}'.format(
|
||||
proto.cls_name,
|
||||
proto.chain_name.upper(),
|
||||
rpc.chain.upper() ))
|
||||
if rpc.chain not in proto.chain_names:
|
||||
raise RPCChainMismatch('\n'+fmt(f"""
|
||||
Protocol: {proto.cls_name}
|
||||
Valid chain names: {fmt_list(proto.chain_names,fmt='bare')}
|
||||
RPC client chain: {rpc.chain}
|
||||
""",indent=' ').rstrip())
|
||||
|
||||
if g.bogus_wallet_data:
|
||||
rpc.blockcount = 1000000
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from mmgen.exception import *
|
|||
|
||||
from mmgen.protocol import init_proto
|
||||
from mmgen.rpc import rpc_init,MoneroWalletRPCClient
|
||||
from mmgen.daemon import CoinDaemon,MoneroWalletDaemon,bitcoin_core_daemon
|
||||
from mmgen.daemon import CoinDaemon,MoneroWalletDaemon
|
||||
|
||||
def auth_test(proto,d):
|
||||
if g.platform != 'win':
|
||||
|
|
@ -82,7 +82,6 @@ def run_test(coin,auth):
|
|||
if auth:
|
||||
auth_test(proto,d)
|
||||
|
||||
qmsg(' OK')
|
||||
return True
|
||||
|
||||
class unit_tests:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue