From 6f0e51d5667b3bb62ab26b50a6f3698cc4294e86 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 8 Feb 2020 17:43:59 +0000 Subject: [PATCH] Daemon: handle path and RPC port selection logic in class --- mmgen/daemon.py | 59 ++++++++++++++++---------- mmgen/main_autosign.py | 4 +- mmgen/main_regtest.py | 1 - mmgen/opts.py | 10 ++--- mmgen/regtest.py | 39 +++++++---------- test/common.py | 4 +- test/start-coin-daemons.py | 9 ++-- test/test-release.sh | 2 +- test/test.py | 2 +- test/test_py_d/ts_ethdev.py | 2 +- test/test_py_d/ts_ref_altcoin.py | 2 +- test/test_py_d/ts_regtest.py | 3 ++ test/unit_tests_d/ut_tx_deserialize.py | 4 +- 13 files changed, 72 insertions(+), 69 deletions(-) diff --git a/mmgen/daemon.py b/mmgen/daemon.py index 2883cae3..c0a7d14c 100755 --- a/mmgen/daemon.py +++ b/mmgen/daemon.py @@ -31,18 +31,17 @@ class Daemon(MMGenObject): subclasses_must_implement = ('state','stop_cmd') - network_ids = ('btc','btc_tn','bch','bch_tn','ltc','ltc_tn','xmr','eth','etc') + network_ids = ('btc','btc_tn','btc_rt','bch','bch_tn','bch_rt','ltc','ltc_tn','ltc_rt','xmr','eth','etc') - cd = namedtuple('coin_data',['coin','coind_exec','cli_exec','conf_file','dfl_rpc','dfl_rpc_tn']) + cd = namedtuple('daemon_data',['coin','coind_exec','cli_exec','conf_file','dfl_rpc','dfl_rpc_tn','dfl_rpc_rt']) daemon_ids = { - 'btc': cd('Bitcoin', 'bitcoind', 'bitcoin-cli', 'bitcoin.conf', 8333,18333), - 'bch': cd('Bcash', 'bitcoind-abc','bitcoin-cli', 'bitcoin.conf', 8442,18442), # MMGen RPC dfls - 'ltc': cd('Litecoin', 'litecoind', 'litecoin-cli','litecoin.conf', 9333,19335), - 'xmr': cd('Monero', 'monerod', 'monerod', 'bitmonero.conf',18082,28082), - 'eth': cd('Ethereum', 'parity', 'parity', 'parity.conf', 8545,8545), - 'etc': cd('Ethereum Classic','parity', 'parity', 'parity.conf', 8545,8545) + 'btc': cd('Bitcoin', 'bitcoind', 'bitcoin-cli', 'bitcoin.conf', 8333,18333,18444), + 'bch': cd('Bcash', 'bitcoind-abc','bitcoin-cli', 'bitcoin.conf', 8442,18442,18553),# MMGen RPC dfls + 'ltc': cd('Litecoin', 'litecoind', 'litecoin-cli','litecoin.conf', 9333,19335,19446), + 'xmr': cd('Monero', 'monerod', 'monerod', 'bitmonero.conf',18082,None,None), + 'eth': cd('Ethereum', 'parity', 'parity', 'parity.conf', 8545,None,None), + 'etc': cd('Ethereum Classic','parity', 'parity', 'parity.conf', 8545,None,None) } - port_shift = 1000 debug = False wait = True @@ -63,20 +62,27 @@ class Daemon(MMGenObject): usr_cli_args = [] usr_shared_args = [] - usr_rpc_port = None - - def __new__(cls,network_id,datadir=None,rpc_port=None,desc='test suite daemon'): - + def __new__(cls,network_id,test_suite=False): network_id = network_id.lower() assert network_id in cls.network_ids, '{!r}: invalid network ID'.format(network_id) - if not datadir: # hack for throwaway instances - datadir = '/tmp/foo' - assert os.path.isabs(datadir), '{!r}: invalid datadir (not an absolute path)'.format(datadir) + if test_suite: + rel_datadir = os.path.join('test','daemons') + desc = 'test suite daemon' + elif not network_id.endswith('_rt'): + raise RuntimeError('only test suite and regtest supported') if network_id.endswith('_tn'): daemon_id = network_id[:-3] network = 'testnet' + elif network_id.endswith('_rt'): + daemon_id = network_id[:-3] + network = 'regtest' + desc = 'regtest daemon' + if test_suite: + rel_datadir = os.path.join('test','data_dir','regtest') + else: + rel_datadir = os.path.join(g.data_dir_root,'regtest') else: daemon_id = network_id network = 'mainnet' @@ -86,25 +92,32 @@ class Daemon(MMGenObject): else EthereumDaemon if daemon_id in ('eth','etc') else BitcoinDaemon ) + if test_suite: + me.datadir = os.path.abspath(os.path.join(os.getcwd(),rel_datadir,daemon_id)) + me.port_shift = 1237 + else: + me.datadir = os.path.join(rel_datadir,daemon_id) + me.port_shift = 0 + me.network_id = network_id me.daemon_id = daemon_id me.network = network - me.datadir = datadir - me.platform = g.platform me.desc = desc - me.usr_rpc_port = rpc_port + me.platform = g.platform return me - def __init__(self,network_id,datadir=None,rpc_port=None,desc='test suite daemon'): + def __init__(self,network_id,test_suite=False): self.pidfile = '{}/{}-daemon.pid'.format(self.datadir,self.network) for k in self.daemon_ids[self.daemon_id]._fields: setattr(self,k,getattr(self.daemon_ids[self.daemon_id],k)) - self.rpc_port = self.usr_rpc_port or ( - (self.dfl_rpc,self.dfl_rpc_tn)[self.network=='testnet'] + self.port_shift - ) + self.rpc_port = { + 'mainnet': self.dfl_rpc, + 'testnet': self.dfl_rpc_tn, + 'regtest': self.dfl_rpc_rt, + }[self.network] + self.port_shift self.net_desc = '{} {}'.format(self.coin,self.network) self.subclass_init() diff --git a/mmgen/main_autosign.py b/mmgen/main_autosign.py index 5dba51f4..f1c8623b 100755 --- a/mmgen/main_autosign.py +++ b/mmgen/main_autosign.py @@ -136,7 +136,7 @@ def check_daemons_running(): continue if g.test_suite: g.proto.daemon_data_dir = 'test/daemons/' + coin.lower() - g.rpc_port = Daemon(get_network_id(coin,g.testnet)).rpc_port + g.rpc_port = Daemon(get_network_id(coin,g.testnet),test_suite=True).rpc_port vmsg('Checking {} daemon'.format(coin)) try: rpc_init(reinit=True) @@ -199,7 +199,7 @@ def sign_tx_file(txfile,signed_txs): if g.proto.sign_mode == 'daemon': if g.test_suite: g.proto.daemon_data_dir = 'test/daemons/' + g.coin.lower() - g.rpc_port = Daemon(get_network_id(g.coin,g.testnet)).rpc_port + g.rpc_port = Daemon(get_network_id(g.coin,g.testnet),test_suite=True).rpc_port rpc_init(reinit=True) if txsign(tx,wfs,None,None): diff --git a/mmgen/main_regtest.py b/mmgen/main_regtest.py index 5e16aee8..78552cf9 100755 --- a/mmgen/main_regtest.py +++ b/mmgen/main_regtest.py @@ -79,5 +79,4 @@ elif cmd_args[0] not in MMGenRegtest.usr_cmds: die(1,'{!r}: invalid command'.format(cmd_args[0])) elif cmd_args[0] not in ('cli','balances'): check_num_args() - MMGenRegtest(g.coin).cmd(cmd_args) diff --git a/mmgen/opts.py b/mmgen/opts.py index 836629da..8d768309 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -318,10 +318,10 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False): g.proto = CoinProtocol(g.coin,g.testnet) g.rpc_host = 'localhost' g.data_dir = os.path.join(g.data_dir_root,'regtest',g.coin.lower(),('alice','bob')[g.bob]) - from mmgen.regtest import MMGenRegtest as rt - g.rpc_port = rt.rpc_ports[g.coin.lower()] - g.rpc_user = rt.rpc_user - g.rpc_password = rt.rpc_password + from mmgen.regtest import MMGenRegtest + g.rpc_user = MMGenRegtest.rpc_user + g.rpc_password = MMGenRegtest.rpc_password + g.rpc_port = MMGenRegtest(g.coin).d.rpc_port check_or_create_dir(g.data_dir) # g.data_dir is finalized, so now we can do this @@ -537,7 +537,7 @@ def check_opts(usr_opts): # Returns false if any check fails elif key in ('bob','alice'): m = "Regtest (Bob and Alice) mode not set up yet. Run '{}-regtest setup' to initialize." from mmgen.regtest import MMGenRegtest - try: os.stat(os.path.join(MMGenRegtest(g.coin).data_dir,'regtest','debug.log')) + try: os.stat(os.path.join(MMGenRegtest(g.coin).d.datadir,'regtest','debug.log')) except: die(1,m.format(g.proj_name.lower())) elif key == 'locktime': if not opt_is_int(val,desc): return False diff --git a/mmgen/regtest.py b/mmgen/regtest.py index b9f33b87..c12a10b3 100755 --- a/mmgen/regtest.py +++ b/mmgen/regtest.py @@ -25,11 +25,6 @@ from subprocess import run,PIPE from mmgen.common import * from mmgen.daemon import Daemon -# To enforce MMGen policy that all testing must ignore the user's ~/.bitcoin -# dir, locate the daemon datadir under MMGen data_dir: -def dfl_data_dir(coin): - return os.path.abspath(os.path.join(g.data_dir_root,'regtest',coin.lower())) - def create_data_dir(data_dir): try: os.stat(os.path.join(data_dir,'regtest')) except: pass @@ -73,7 +68,6 @@ class RegtestDaemon(MMGenObject): # mixin class class MMGenRegtest(MMGenObject): - rpc_ports = { 'btc':8552, 'bch':8553, 'ltc':8555 } rpc_user = 'bobandalice' rpc_password = 'hodltothemoon' users = ('bob','alice','miner') @@ -83,23 +77,22 @@ class MMGenRegtest(MMGenObject): 'setup','generate','send','stop', 'balances','mempool','cli' ) - def __init__(self,coin,datadir=None): + def __init__(self,coin): self.coin = coin.lower() - self.data_dir = datadir or dfl_data_dir(self.coin) - self.rpc_port = self.rpc_ports[self.coin] + self.test_suite = os.getenv('MMGEN_TEST_SUITE_REGTEST') + self.d = Daemon(self.coin+'_rt',test_suite=self.test_suite) assert self.coin in self.coins,'{!r}: invalid coin for regtest'.format(user) - assert os.path.isabs(self.data_dir), '{!r}: invalid datadir (not an absolute path)'.format(datadir) def setup(self): - try: os.makedirs(self.data_dir) + try: os.makedirs(self.d.datadir) except: pass if self.daemon_state() != 'stopped': self.stop_daemon() - create_data_dir(self.data_dir) + create_data_dir(self.d.datadir) gmsg('Starting {} regtest setup'.format(self.coin)) @@ -134,7 +127,7 @@ class MMGenRegtest(MMGenObject): assert user is None or user in self.users,'{!r}: invalid user for regtest'.format(user) - d = Daemon(self.coin,self.data_dir,desc='regtest daemon',rpc_port=self.rpc_port) + d = Daemon(self.coin+'_rt',test_suite=self.test_suite) type(d).generate = RegtestDaemon.generate @@ -163,7 +156,7 @@ class MMGenRegtest(MMGenObject): msg(err) def current_user_unix(self,quiet=False): - cmd = ['pgrep','-af','{}.*--rpcport={}.*'.format(g.proto.daemon_name,self.rpc_port)] + cmd = ['pgrep','-af','{}.*--rpcport={}.*'.format(g.proto.daemon_name,self.d.rpc_port)] cmdout = run(cmd,stdout=PIPE).stdout.decode() if cmdout: for k in self.users: @@ -176,7 +169,7 @@ class MMGenRegtest(MMGenObject): if self.daemon_state() == 'stopped': return None - debug_logfile = os.path.join(self.data_dir,'regtest','debug.log') + debug_logfile = os.path.join(self.d.datadir,'regtest','debug.log') fd = os.open(debug_logfile,os.O_RDONLY|os.O_BINARY) file_size = os.fstat(fd).st_size @@ -283,10 +276,10 @@ class MMGenRegtest(MMGenObject): gmsg('Creating fork from coin {} to coin {}'.format(coin,g.coin)) - source_rt = MMGenRegtest(coin,dfl_data_dir(coin)) + source_rt = MMGenRegtest(coin) - try: os.stat(source_rt.data_dir) - except: die(1,"Source directory '{}' does not exist!".format(source_rt.data_dir)) + try: os.stat(source_rt.d.datadir) + except: die(1,"Source directory '{}' does not exist!".format(source_rt.d.datadir)) # stop the source daemon if source_rt.daemon_state() != 'stopped': @@ -296,14 +289,12 @@ class MMGenRegtest(MMGenObject): if self.daemon_state() != 'stopped': self.stop_daemon() - data_dir = dfl_data_dir(g.coin) - - try: os.makedirs(data_dir) + try: os.makedirs(self.d.datadir) except: pass - create_data_dir(data_dir) - os.rmdir(data_dir) - shutil.copytree(source_data_dir,data_dir,symlinks=True) + create_data_dir(self.d.datadir) + os.rmdir(self.d.datadir) + shutil.copytree(source_data_dir,self.d.datadir,symlinks=True) self.start_daemon('miner',reindex=True) self.stop_daemon() diff --git a/test/common.py b/test/common.py index ac08acd5..fb2e6fdb 100755 --- a/test/common.py +++ b/test/common.py @@ -175,10 +175,8 @@ def test_daemons_ops(*network_ids,op): if opt.no_daemon_autostart: return from mmgen.daemon import Daemon - repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),os.pardir))) silent = not opt.verbose and not (hasattr(opt,'exact_output') and opt.exact_output) for network_id in network_ids: if network_id not in Daemon.network_ids: # silently ignore invalid IDs continue - datadir = '{}/test/daemons/{}'.format(repo_root,network_id.replace('_tn','')) - Daemon(network_id,datadir).cmd(op,silent=silent) + Daemon(network_id,test_suite=True).cmd(op,silent=silent) diff --git a/test/start-coin-daemons.py b/test/start-coin-daemons.py index f21a6288..de912dd8 100755 --- a/test/start-coin-daemons.py +++ b/test/start-coin-daemons.py @@ -64,13 +64,12 @@ if 'eth' in ids and 'etc' in ids: for network_id in ids: network_id = network_id.lower() - coin = network_id.replace('_tn','') if opt.regtest_user: - datadir = '{}/test/data_dir/regtest/{}'.format(repo_root,coin) - d = MMGenRegtest(network_id,datadir).test_daemon(opt.regtest_user) + d = MMGenRegtest(network_id).test_daemon(opt.regtest_user) else: - datadir = '{}/test/daemons/{}'.format(repo_root,coin) - d = Daemon(network_id,datadir) + if network_id.endswith('_rt'): + continue + d = Daemon(network_id,test_suite=True) d.debug = opt.debug d.wait = not opt.no_wait if opt.get_state: diff --git a/test/test-release.sh b/test/test-release.sh index ad84771e..35160987 100755 --- a/test/test-release.sh +++ b/test/test-release.sh @@ -327,7 +327,7 @@ t_xmr=" " f_xmr='Monero tests completed' -mmgen_tool_xmr="$mmgen_tool --rpc-port=19082 -q --accept-defaults --outdir $TMPDIR" +mmgen_tool_xmr="$mmgen_tool --rpc-port=19319 -q --accept-defaults --outdir $TMPDIR" [ "$MSYS2" ] || { # password file descriptor issues, cannot use popen_spawn() t_xmr+=" diff --git a/test/test.py b/test/test.py index c3286a51..e60c2b21 100755 --- a/test/test.py +++ b/test/test.py @@ -156,7 +156,7 @@ network_id = get_network_id(get_coin(),bool(_uopts.get('testnet'))) sys.argv.insert(1,'--data-dir=' + data_dir) sys.argv.insert(1,'--daemon-data-dir=test/daemons/' + get_coin()) -sys.argv.insert(1,'--rpc-port={}'.format(Daemon(network_id).rpc_port)) +sys.argv.insert(1,'--rpc-port={}'.format(Daemon(network_id,test_suite=True).rpc_port)) # step 2: opts.init will create new data_dir in ./test (if not 'resume' or 'skip_deps'): usr_args = opts.init(opts_data) diff --git a/test/test_py_d/ts_ethdev.py b/test/test_py_d/ts_ethdev.py index 06276ce4..725976ae 100755 --- a/test/test_py_d/ts_ethdev.py +++ b/test/test_py_d/ts_ethdev.py @@ -300,7 +300,7 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): def __init__(self,trunner,cfgs,spawn): from mmgen.daemon import Daemon - self.rpc_port = Daemon(g.coin).rpc_port + self.rpc_port = Daemon(g.coin,test_suite=True).rpc_port os.environ['MMGEN_BOGUS_WALLET_DATA'] = '' return TestSuiteBase.__init__(self,trunner,cfgs,spawn) diff --git a/test/test_py_d/ts_ref_altcoin.py b/test/test_py_d/ts_ref_altcoin.py index 9d5f53c1..c2c28c99 100755 --- a/test/test_py_d/ts_ref_altcoin.py +++ b/test/test_py_d/ts_ref_altcoin.py @@ -97,7 +97,7 @@ class TestSuiteRefAltcoin(TestSuiteRef,TestSuiteBase): start_test_daemons(network_id) extra_opts += [ '--daemon-data-dir=test/daemons/bch', - '--rpc-port={}'.format(Daemon(network_id).rpc_port) ] + '--rpc-port={}'.format(Daemon(network_id,test_suite=True).rpc_port) ] g.testnet = tn init_coin(coin) fn = TestSuiteRef.sources['ref_tx_file'][token or coin][bool(tn)] diff --git a/test/test_py_d/ts_regtest.py b/test/test_py_d/ts_regtest.py index 0d17079b..e9af946b 100755 --- a/test/test_py_d/ts_regtest.py +++ b/test/test_py_d/ts_regtest.py @@ -231,6 +231,9 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): usr_subsids = { 'bob': {}, 'alice': {} } def __init__(self,trunner,cfgs,spawn): + os.environ['MMGEN_TEST_SUITE_REGTEST'] = '1' + from mmgen.regtest import MMGenRegtest + rt = MMGenRegtest(g.coin) coin = g.coin.lower() for k in rt_data: globals()[k] = rt_data[k][coin] if coin in rt_data[k] else None diff --git a/test/unit_tests_d/ut_tx_deserialize.py b/test/unit_tests_d/ut_tx_deserialize.py index 7ae5d5fd..b9a68c0d 100755 --- a/test/unit_tests_d/ut_tx_deserialize.py +++ b/test/unit_tests_d/ut_tx_deserialize.py @@ -112,11 +112,11 @@ class unit_test(object): for n,(coin,tn,fn) in enumerate(fns): init_coin(coin,tn) g.proto.daemon_data_dir = 'test/daemons/' + g.coin.lower() - g.rpc_port = Daemon(coin + ('','_tn')[tn]).rpc_port + g.rpc_port = Daemon(coin + ('','_tn')[tn],test_suite=True).rpc_port rpc_init(reinit=True) test_tx(MMGenTX(fn).hex,fn,n+1) init_coin('btc',False) - g.rpc_port = Daemon('btc').rpc_port + g.rpc_port = Daemon('btc',test_suite=True).rpc_port rpc_init(reinit=True) Msg('OK')