From f4d2829a548b851a76aee3f5a314826957d49535 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 25 Feb 2020 16:45:27 +0000 Subject: [PATCH] Daemon: new 'flags' arg; testing/release: minor fixes --- doc/release-notes/release-notes-v0.12.0.md | 15 +++++-- mmgen/daemon.py | 51 +++++++++++++++++++--- mmgen/seed.py | 2 +- test/common.py | 2 +- test/start-coin-daemons.py | 3 +- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/doc/release-notes/release-notes-v0.12.0.md b/doc/release-notes/release-notes-v0.12.0.md index d9bad759..b8fdbb33 100644 --- a/doc/release-notes/release-notes-v0.12.0.md +++ b/doc/release-notes/release-notes-v0.12.0.md @@ -19,8 +19,9 @@ - New Tool API interface: f8056630 - New [Daemon control interface][dc] and [test daemon start/stop utilities][ss] - Full automation of test suite with automatic starting/stopping of daemons + - New wiki documentation for the [Test Suite][ts] and [Tool API][ta] - UTF8 password entry works reliably under MSYS2, warnings disabled - - Plus lots of code cleanups, bugfixes, new tests and [expanded documentation][w] + - Plus lots of code reorganization, cleanups, bugfixes and new tests! This release has been tested on the following platforms: @@ -36,7 +37,12 @@ and with the following coin daemon versions: Bitcoin-ABC 0.21.0 Litecoin Core 0.17.1 Monerod 0.15.0.1 - Parity Ethereum 2.7.2 + Parity Ethereum 2.7.2* + + * Parity crashes on startup on some systems when in developer mode, + causing the 'eth' test to fail. This is a problem with Parity, not + MMGen. On cleanly installed systems, Parity and the 'eth' test ran + without issue on all tested platforms. Altcoin address generation has been additionally tested using the following tools as references: @@ -45,7 +51,8 @@ tools as references: pycoin 11f60a7c (https://github.com/richardkiss/pycoin) vanitygen-plus 22123128 (https://github.com/exploitagency/vanitygen-plus) -[xo]: https://github.com/mmgen/mmgen/wiki/XOR-Seed-Splitting:-Theory-and-Practice.md +[xo]: https://github.com/mmgen/mmgen/wiki/XOR-Seed-Splitting:-Theory-and-Practice [dc]: https://github.com/mmgen/mmgen/blob/master/mmgen/daemon.py [ss]: https://github.com/mmgen/mmgen/blob/master/test/start-coin-daemons.py -[w]: https://github.com/mmgen/mmgen/wiki +[ts]: https://github.com/mmgen/mmgen/wiki/Test-Suite +[ta]: https://github.com/mmgen/mmgen/wiki/Tool-API diff --git a/mmgen/daemon.py b/mmgen/daemon.py index 71783d9c..dbe8e758 100755 --- a/mmgen/daemon.py +++ b/mmgen/daemon.py @@ -35,6 +35,8 @@ class Daemon(MMGenObject): new_console_mswin = False ps_pid_mswin = False lockfile = None + avail_flags = () + _flags = [] def subclass_init(self): pass @@ -180,6 +182,26 @@ class Daemon(MMGenObject): for k in cls.subclasses_must_implement: assert k in subcls.__dict__, m.format(k,subcls.__name__) + @property + def flags(self): + return self._flags + + def add_flag(self,val): + if val not in self.avail_flags: + m = '{!r}: unrecognized flag (available options: {})' + die(1,m.format(val,self.avail_flags)) + if val in self._flags: + die(1,'Flag {!r} already set'.format(val)) + self._flags.append(val) + + def remove_flag(self,val): + if val not in self.avail_flags: + m = '{!r}: unrecognized flag (available options: {})' + die(1,m.format(val,self.avail_flags)) + if val not in self._flags: + die(1,'Flag {!r} not set, so cannot be removed'.format(val)) + self._flags.remove(val) + class MoneroWalletDaemon(Daemon): desc = 'RPC daemon' @@ -223,7 +245,8 @@ class MoneroWalletDaemon(Daemon): '--log-file='+self.logfile, '--rpc-login={}:{}'.format(g.monero_wallet_rpc_user,g.monero_wallet_rpc_password) ] if self.platform == 'linux': - cmd += ['--pidfile={}'.format(self.pidfile),'--detach'] + cmd += ['--pidfile={}'.format(self.pidfile)] + cmd += [] if 'no_daemonize' in self.flags else ['--detach'] return cmd @property @@ -248,6 +271,7 @@ class MoneroWalletDaemon(Daemon): class CoinDaemon(Daemon): cfg_file_hdr = '' subclasses_must_implement = ('state','stop_cmd') + avail_flags = ('no_daemonize',) network_ids = ('btc','btc_tn','btc_rt','bch','bch_tn','bch_rt','ltc','ltc_tn','ltc_rt','xmr','eth','etc') @@ -265,6 +289,7 @@ class CoinDaemon(Daemon): testnet_arg = [] coind_args = [] + daemonize_args = [] cli_args = [] shared_args = [] coind_cmd = [] @@ -277,7 +302,8 @@ class CoinDaemon(Daemon): usr_cli_args = [] usr_shared_args = [] - def __new__(cls,network_id,test_suite=False): + def __new__(cls,network_id,test_suite=False,flags=None): + network_id = network_id.lower() assert network_id in cls.network_ids, '{!r}: invalid network ID'.format(network_id) @@ -321,7 +347,14 @@ class CoinDaemon(Daemon): me.platform = g.platform return me - def __init__(self,network_id,test_suite=False): + def __init__(self,network_id,test_suite=False,flags=None): + + if flags: + if type(flags) not in (list,tuple): + m = '{!r}: illegal value for flags (must be list or tuple)' + die(1,m.format(flags)) + for flag in flags: + self.add_flag(flag) self.pidfile = '{}/{}-daemon.pid'.format(self.datadir,self.network) @@ -347,6 +380,7 @@ class CoinDaemon(Daemon): + self.coin_specific_shared_args + self.usr_coind_args + self.usr_shared_args + + self.daemonize_args + self.coind_cmd ) def cli_cmd(self,*cmds): @@ -384,8 +418,8 @@ class BitcoinDaemon(CoinDaemon): if self.use_pidfile: self.coind_args += ['--pid='+self.pidfile] - if self.platform == 'linux': - self.coind_args += ['--daemon'] + if self.platform == 'linux' and not 'no_daemonize' in self.flags: + self.daemonize_args = ['--daemon'] if self.daemon_id == 'bch': self.coin_specific_coind_args = ['--usecashaddr=0'] @@ -439,7 +473,8 @@ class MoneroDaemon(CoinDaemon): '--data-dir={}'.format(self.datadir), '--offline' ] if self.platform == 'linux': - cmd += ['--pidfile={}'.format(self.pidfile),'--detach'] + cmd += ['--pidfile={}'.format(self.pidfile)] + cmd += [] if 'no_daemonize' in self.flags else ['--detach'] return cmd @property @@ -472,10 +507,12 @@ class EthereumDaemon(CoinDaemon): # win: $LOCALAPPDATA/Parity/Ethereum/chains/DevelopmentChain self.chaindir = os.path.join(self.datadir,'devchain') shutil.rmtree(self.chaindir,ignore_errors=True) + if self.platform == 'linux' and not 'no_daemonize' in self.flags: + self.daemonize_args = ['daemon',self.pidfile] @property def coind_cmd(self): - return ['daemon',self.pidfile] if self.platform == 'linux' else [] + return [] @property def coind_args(self): diff --git a/mmgen/seed.py b/mmgen/seed.py index 95fc53ff..5107a4ae 100755 --- a/mmgen/seed.py +++ b/mmgen/seed.py @@ -1122,7 +1122,7 @@ class PlainHexSeedFile(SeedSourceUnenc): d = self.fmt_data.strip() if not is_hex_str_lc(d): - msg("'{}': not a lowercase hexidecimal string, in {}".format(d,desc)) + msg("'{}': not a lowercase hexadecimal string, in {}".format(d,desc)) return False if not len(d)*4 in g.seed_lens: diff --git a/test/common.py b/test/common.py index 08664322..b2a2d7e4 100755 --- a/test/common.py +++ b/test/common.py @@ -23,7 +23,7 @@ common.py: Shared routines and data for the MMGen test suites class TestSuiteException(Exception): pass class TestSuiteFatalException(Exception): pass -import os,time +import os from mmgen.common import * from mmgen.devtools import * diff --git a/test/start-coin-daemons.py b/test/start-coin-daemons.py index e6195212..17f89af1 100755 --- a/test/start-coin-daemons.py +++ b/test/start-coin-daemons.py @@ -17,6 +17,7 @@ opts_data = { -h, --help Print this help message --, --longhelp Print help message for long options (common options) -d, --debug Produce debugging output (implies --verbose) +-D, --no-daemonize Don't fork daemon to background -r, --regtest-user=U {a} a regtest daemon for user 'U' -s, --get-state Get the state of the daemon(s) and exit -t, --testing Testing mode. Print commands but don't execute them @@ -69,7 +70,7 @@ for network_id in ids: else: if network_id.endswith('_rt'): continue - d = CoinDaemon(network_id,test_suite=True) + d = CoinDaemon(network_id,test_suite=True,flags=['no_daemonize'] if opt.no_daemonize else None) d.debug = opt.debug d.wait = not opt.no_wait if opt.get_state: