stop Monero coin and wallet daemons via RPC

This commit is contained in:
The MMGen Project 2021-10-10 20:18:16 +00:00
commit 35f9201174
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
8 changed files with 89 additions and 32 deletions

View file

@ -306,6 +306,9 @@ class MoneroWalletDaemon(RPCDaemon):
['--stagenet', self.network == 'testnet'],
)
from .rpc import MoneroWalletRPCClient
self.rpc = MoneroWalletRPCClient( daemon=self, test_connection=False )
class CoinDaemon(Daemon):
networks = ('mainnet','testnet','regtest')
cfg_file_hdr = ''
@ -622,6 +625,15 @@ class monero_daemon(CoinDaemon):
def init_subclass(self):
from .rpc import MoneroRPCClientRaw
self.rpc = MoneroRPCClientRaw(
host = self.host,
port = self.rpc_port,
user = None,
passwd = None,
test_connection = False,
daemon = self )
self.shared_args = list_gen(
[f'--no-zmq'],
[f'--p2p-bind-port={self.p2p_port}', self.p2p_port],

View file

@ -234,4 +234,4 @@ try:
except KeyboardInterrupt:
ymsg('\nUser interrupt')
finally:
m.stop_daemons()
run_session(m.stop_wallet_daemon())

View file

@ -403,6 +403,23 @@ class RPCClient(MMGenObject):
except: m = text
raise RPCFailure(f'{s.value} {s.name}: {m}')
async def stop_daemon(self,quiet=False,silent=False):
if self.daemon.state == 'ready':
if not (quiet or silent):
msg(f'Stopping {self.daemon.desc} on port {self.daemon.bind_port}')
ret = await self.do_stop_daemon(silent=silent)
if self.daemon.wait:
self.daemon.wait_for_state('stopped')
return ret
else:
if not (quiet or silent):
msg(f'{self.daemon.desc} on port {self.daemon.bind_port} not running')
return True
async def restart_daemon(self,quiet=False,silent=False):
await self.stop_daemon(quiet=quiet,silent=silent)
return self.daemon.start(silent=silent)
class BitcoinRPCClient(RPCClient,metaclass=AsyncInit):
auth_type = 'basic'
@ -657,7 +674,7 @@ class MoneroRPCClient(RPCClient):
host_path = '/json_rpc'
verify_server = False
def __init__(self,host,port,user,passwd,test_connection=True,proxy=None):
def __init__(self,host,port,user,passwd,test_connection=True,proxy=None,daemon=None):
if proxy is not None:
from .obj import IPPort
self.proxy = IPPort(proxy)
@ -673,6 +690,7 @@ class MoneroRPCClient(RPCClient):
self.set_backend('curl')
self.backend.exec_opts.remove('--silent')
self.backend.exec_opts.append('--verbose')
self.daemon = daemon
async def call(self,method,*params,**kwargs):
assert params == (), f'{type(self).__name__}.call() accepts keyword arguments only'
@ -701,7 +719,10 @@ class MoneroRPCClientRaw(MoneroRPCClient):
def make_host_path(arg):
return arg
rpcmethods = ( 'get_height', 'send_raw_transaction' )
async def do_stop_daemon(self,silent=False):
return await self.call('stop_daemon')
rpcmethods = ( 'get_height', 'send_raw_transaction', 'stop_daemon' )
class MoneroWalletRPCClient(MoneroRPCClient):
@ -731,6 +752,13 @@ class MoneroWalletRPCClient(MoneroRPCClient):
'refresh', # start_height
)
async def do_stop_daemon(self,silent=False):
"""
NB: the 'stop_wallet' RPC call closes the open wallet before shutting down the daemon,
returning an error if no wallet is open
"""
return await self.call('stop_wallet')
class daemon_warning(oneshot_warning_group):
class geth:

View file

@ -295,7 +295,8 @@ class MoneroWalletOps:
def post_main(self):
pass
def stop_daemons(self): pass
async def stop_wallet_daemon(self):
pass
class wallet(base):
@ -338,10 +339,10 @@ class MoneroWalletOps:
daemon_addr = uopt.daemon or None,
)
if not uopt.no_start_wallet_daemon:
self.wd.restart()
self.c = MoneroWalletRPCClient(daemon=self.wd,test_connection=False)
self.c = MoneroWalletRPCClient(daemon=self.wd)
if not uopt.no_start_wallet_daemon:
run_session(self.c.restart_daemon())
def create_addr_data(self):
if uarg.wallets:
@ -352,11 +353,9 @@ class MoneroWalletOps:
else:
self.addr_data = self.kal.data
def stop_daemons(self):
async def stop_wallet_daemon(self):
if not uopt.no_stop_wallet_daemon:
self.wd.stop()
if uopt.tx_relay_daemon and hasattr(self,'wd2'):
self.wd2.stop()
await self.c.stop_daemon()
def get_wallet_fn(self,d):
return os.path.join(
@ -415,6 +414,12 @@ class MoneroWalletOps:
await self.c.call('close_wallet')
gmsg_r('done')
async def stop_wallet(self,desc):
msg(f'Stopping {self.c.daemon.desc} on port {self.c.daemon.bind_port}')
gmsg_r(f'\n Stopping {desc} wallet...')
await self.c.stop_daemon(quiet=True) # closes wallet
gmsg_r('done')
def print_accts(self,data,addrs_data,indent=' '):
d = data['subaddress_accounts']
msg('\n' + indent + f'Accounts of wallet {os.path.basename(self.fn)}:')
@ -658,7 +663,9 @@ class MoneroWalletOps:
t_elapsed // 60,
t_elapsed % 60 ))
await self.c.call('close_wallet')
if not last:
await self.c.call('close_wallet')
return wallet_height >= chain_height
def post_main(self):
@ -724,20 +731,19 @@ class MoneroWalletOps:
m = re.fullmatch(uarg_info['tx_relay_daemon'].pat,uopt.tx_relay_daemon,re.ASCII)
self.wd2 = MoneroWalletDaemon(
wd2 = MoneroWalletDaemon(
proto = self.proto,
wallet_dir = uopt.wallet_dir or '.',
test_suite = g.test_suite,
daemon_addr = m[1],
proxy = m[2],
port_shift = 16 )
proxy = m[2] )
if g.test_suite:
self.wd2.usr_daemon_args = ['--daemon-ssl-allow-any-cert']
wd2.usr_daemon_args = ['--daemon-ssl-allow-any-cert']
self.wd2.start()
wd2.start()
self.c = MoneroWalletRPCClient(daemon=self.wd2)
self.c = MoneroWalletRPCClient(daemon=wd2)
async def main(self):
gmsg(f'\n{self.desc}ing account #{self.account} of wallet {self.source.idx}' + (
@ -808,7 +814,7 @@ class MoneroWalletOps:
elif keypress_confirm(f'Relay {self.name} transaction?'):
w_desc = 'source'
if uopt.tx_relay_daemon:
await h.close_wallet('source')
await h.stop_wallet('source')
msg('')
self.init_tx_relay_daemon()
h = self.rpc(self,self.source)
@ -816,11 +822,9 @@ class MoneroWalletOps:
await h.open_wallet(w_desc,refresh=False)
msg_r(f'\n Relaying {self.name} transaction...')
await h.relay_tx(new_tx.data.metadata)
await h.close_wallet(w_desc)
gmsg('\n\nAll done')
else:
await h.close_wallet('source')
die(1,'\nExiting at user request')
return True

View file

@ -55,7 +55,10 @@ def run(network_id=None,proto=None,daemon_id=None):
for cmd in d.start_cmds if action == 'start' else [d.stop_cmd]:
print(' '.join(cmd))
else:
d.cmd(action,quiet=opt.quiet)
if action == 'stop' and hasattr(d,'rpc'):
run_session(d.rpc.stop_daemon(quiet=opt.quiet))
else:
d.cmd(action,quiet=opt.quiet)
if 'all' in cmd_args or 'no_xmr' in cmd_args:
if len(cmd_args) != 1:

View file

@ -221,6 +221,7 @@ class TestSuiteXMRWallet(TestSuiteBase):
user = None,
passwd = None,
test_connection = False,
daemon = md,
)
md_json_rpc = MoneroRPCClient(
host = md.host,
@ -228,6 +229,7 @@ class TestSuiteXMRWallet(TestSuiteBase):
user = None,
passwd = None,
test_connection = False,
daemon = md,
)
wd = MoneroWalletDaemon(
proto = self.proto,
@ -659,11 +661,7 @@ class TestSuiteXMRWallet(TestSuiteBase):
def stop_daemons(self):
for v in self.users.values():
if v.md.state != 'stopped':
v.md.stop()
def start_wallet_daemons(self):
self.users['miner'].wd.start()
run_session(v.md_rpc.stop_daemon())
def stop_miner_wallet_daemon(self):
self.users['miner'].wd.stop()
run_session(self.users['miner'].wd_rpc.stop_daemon())

View file

@ -82,7 +82,10 @@ def test_cmds(op):
else:
if opt.quiet:
msg_r('.')
getattr(d,op)(silent=opt.quiet)
if op == 'stop' and hasattr(d,'rpc'):
run_session(d.rpc.stop_daemon(quiet=opt.quiet))
else:
getattr(d,op)(silent=opt.quiet)
class unit_tests:

View file

@ -125,17 +125,26 @@ class unit_tests:
md.start()
wd.start()
c = MoneroWalletRPCClient(daemon=wd)
await c.call('get_version')
fn = f'monero-{wd.network}-junk-wallet'
qmsg(f'Creating {wd.network} wallet')
await c.call(
'restore_deterministic_wallet',
filename = fn,
password = 'foo',
seed = baseconv.fromhex('beadface'*8,'xmrseed',tostr=True) )
qmsg(f'Opening {wd.network} wallet')
await c.call( 'open_wallet', filename=fn, password='foo' )
for md,wd in daemons:
wd.wait = False
wd.stop()
await wd.rpc.stop_daemon()
if not opt.no_daemon_stop:
md.wait = False
md.stop()
await md.rpc.stop_daemon()
gmsg('OK')
from mmgen.baseconv import baseconv
import shutil
shutil.rmtree('test/trash2',ignore_errors=True)
os.makedirs('test/trash2')