From e10f5d19ac74267e2557b76b44ed939a4ab1f15e Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 12 Mar 2021 14:52:58 +0000 Subject: [PATCH] protocol-specific cfg_file vars: fix chain_name parsing regression, add test --- mmgen/opts.py | 5 ++- mmgen/protocol.py | 9 ++++- test/misc/cfg.py | 16 +++++--- test/test_py_d/ts_cfg.py | 81 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 9 deletions(-) diff --git a/mmgen/opts.py b/mmgen/opts.py index f78f274d..6260828b 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -129,7 +129,10 @@ def override_globals_from_cfg_file(ucfg): if d.name in g.cfg_file_opts: ns = d.name.split('_') if ns[0] in CoinProtocol.coins: - nse,tn = (ns[2:],True) if len(ns) > 2 and ns[1] == 'testnet' else (ns[1:],False) + nse,tn = ( + (ns[2:],ns[1]=='testnet') if len(ns) > 2 and ns[1] in ('mainnet','testnet') else + (ns[1:],False) + ) cls = type(init_proto(ns[0],tn)) # no instance yet, so override _class_ attr attr = '_'.join(nse) else: diff --git a/mmgen/protocol.py b/mmgen/protocol.py index dcd35631..b138e1bc 100755 --- a/mmgen/protocol.py +++ b/mmgen/protocol.py @@ -87,7 +87,6 @@ class CoinProtocol(MMGenObject): base_proto = None is_fork_of = None networks = ('mainnet','testnet','regtest') - ignore_daemon_version = False def __init__(self,coin,name,network,tokensym=None): self.coin = coin.upper() @@ -230,6 +229,7 @@ class CoinProtocol(MMGenObject): halving_interval = 210000 max_halvings = 64 start_subsidy = 50 + ignore_daemon_version = False def hex2wif(self,hexpriv,pubkey_type,compressed): # input is preprocessed hex sec = bytes.fromhex(hexpriv) @@ -314,6 +314,7 @@ class CoinProtocol(MMGenObject): caps = () coin_amt = BCHAmt max_tx_fee = BCHAmt('0.1') + ignore_daemon_version = False def pubhex2redeem_script(self,pubhex): raise NotImplementedError def pubhex2segwitaddr(self,pubhex): raise NotImplementedError @@ -332,6 +333,7 @@ class CoinProtocol(MMGenObject): forks = [ finfo(None,'','BTC',True) # activation: 494784 ] + ignore_daemon_version = False class B2XTestnet(B2X): addr_ver_bytes = { '6f': 'p2pkh', 'c4': 'p2sh' } @@ -349,6 +351,7 @@ class CoinProtocol(MMGenObject): bech32_hrp = 'ltc' avg_bdi = 150 halving_interval = 840000 + ignore_daemon_version = False class LitecoinTestnet(Litecoin): # addr ver nums same as Bitcoin testnet, except for 'p2sh' @@ -387,6 +390,7 @@ class CoinProtocol(MMGenObject): mmcaps = ('key','addr','rpc','tx') base_proto = 'Ethereum' avg_bdi = 15 + ignore_daemon_version = False @property def dcoin(self): @@ -413,6 +417,8 @@ class CoinProtocol(MMGenObject): class EthereumClassic(Ethereum): chain_name = 'ethereum_classic' # chain_id 0x3d (61) + max_tx_fee = ETHAmt('0.005') + ignore_daemon_version = False class EthereumClassicTestnet(EthereumClassic): chain_name = 'classic-testnet' # aka Morden, chain_id 0x3e (62) (UNTESTED) @@ -463,6 +469,7 @@ class CoinProtocol(MMGenObject): avg_bdi = 120 privkey_len = 32 mmcaps = ('key','addr') + ignore_daemon_version = False def preprocess_key(self,sec,pubkey_type): # reduce key from .ed25519 import l diff --git a/test/misc/cfg.py b/test/misc/cfg.py index c60fd8b8..30e454cf 100755 --- a/test/misc/cfg.py +++ b/test/misc/cfg.py @@ -13,8 +13,14 @@ msg('usr cfg: {}'.format(cu.fn)) msg('sys cfg: {}'.format(cS.fn)) msg('sample cfg: {}'.format(cs.fn)) -if cmd_args == ['parse_test']: - ps = cs.parse(parse_vars=True) - msg('parsed chunks: {}'.format(len(ps))) - pu = cu.parse() - msg('usr cfg: {}'.format(' '.join(['{}={}'.format(i.name,i.value) for i in pu]))) +if cmd_args: + if cmd_args[0] == 'parse_test': + ps = cs.parse(parse_vars=True) + msg('parsed chunks: {}'.format(len(ps))) + pu = cu.parse() + msg('usr cfg: {}'.format(' '.join(['{}={}'.format(i.name,i.value) for i in pu]))) + elif cmd_args[0] == 'coin_specific_vars': + from mmgen.protocol import init_proto_from_opts + proto = init_proto_from_opts() + for varname in cmd_args[1:]: + print(f'{type(proto).__name__}.{varname}:',getattr(proto,varname)) diff --git a/test/test_py_d/ts_cfg.py b/test/test_py_d/ts_cfg.py index da0ef234..25be328c 100755 --- a/test/test_py_d/ts_cfg.py +++ b/test/test_py_d/ts_cfg.py @@ -29,14 +29,20 @@ class TestSuiteCfg(TestSuiteBase): ('altered_sample', (40,'init with user-modified cfg sample file', [])), ('old_sample', (40,'init with old v2 cfg sample file', [])), ('old_sample_bad_var', (40,'init with old v2 cfg sample file and bad variable in mmgen.cfg', [])), + ('coin_specific_vars', (40,'test setting of coin-specific vars', [])), + ('chain_names', (40,'test setting of chain names', [])), ) def __init__(self,trunner,cfgs,spawn): os.environ['MMGEN_TEST_SUITE_CFGTEST'] = '1' TestSuiteBase.__init__(self,trunner,cfgs,spawn) - def spawn_test(self,args=[]): - return self.spawn('test/misc/cfg.py',['--data-dir={}'.format(self.path('data_dir'))]+args,cmd_dir='.') + def spawn_test(self,args=[],extra_desc=''): + return self.spawn( + 'test/misc/cfg.py', + [f'--data-dir={self.path("data_dir")}'] + args, + cmd_dir = '.', + extra_desc = extra_desc ) def path(self,id_str): return { @@ -148,3 +154,74 @@ class TestSuiteCfg(TestSuiteBase): d = ['foo true','bar false'] write_to_file(self.path('usr'),'\n'.join(d) + '\n') return self.old_sample_common(old_set=True) + + def coin_specific_vars(self): + """ + ensure that derived classes explicitly set these variables + """ + d = [ + 'btc_max_tx_fee 1.2345', + 'eth_max_tx_fee 5.4321', + 'btc_ignore_daemon_version true', + 'eth_ignore_daemon_version true' + ] + write_to_file(self.path('usr'),'\n'.join(d) + '\n') + imsg(yellow('Wrote cfg file:\n {}'.format('\n '.join(d)))) + + for coin,res1_chk,res2_chk,res2_chk_eq in ( + ('BTC','True', '1.2345',True), + ('LTC','False','1.2345',False), + ('BCH','False','1.2345',False), + ('ETH','True', '5.4321',True), + ('ETC','False','5.4321',False) + ): + t = self.spawn_test( + args = [ + f'--coin={coin}', + 'coin_specific_vars', + 'ignore_daemon_version', + 'max_tx_fee' + ], + extra_desc=f'({coin})' ) + res1 = t.expect_getend('ignore_daemon_version: ') + res2 = t.expect_getend('max_tx_fee: ') + assert res1 == res1_chk, f'{res1} != {res1_chk}' + if res2_chk_eq: + assert res2 == res2_chk, f'{res2} != {res2_chk}' + else: + assert res2 != res2_chk, f'{res2} == {res2_chk}' + t.read() + t.ok() + + t.skip_ok = True + return t + + def chain_names(self): + + def run(chk,testnet): + for coin,chain_chk in (('ETH',chk),('ETC',None)): + t = self.spawn_test( + args = [f'--coin={coin}',f'--testnet={(0,1)[testnet]}','coin_specific_vars','chain_name'], + extra_desc = f'({coin} testnet={testnet} chain={chain_chk})' ) + chain = t.expect_getend('chain_name: ') + if chain_chk: + assert chain == chain_chk, f'{chain} != {chain_chk}' + else: + assert chain != chain_chk, f'{chain} == {chain_chk}' + t.read() + t.ok() + return t + + write_to_file(self.path('usr'),'eth_mainnet_chain_name foobar\n') + imsg(yellow('Wrote cfg file: "eth_mainnet_chain_name foobar"')) + t = run('foobar',False) + t = run(None,True) + + write_to_file(self.path('usr'),'eth_testnet_chain_name foobar\n') + imsg(yellow('Wrote cfg file: "eth_testnet_chain_name foobar"')) + t = run(None,False) + t = run('foobar',True) + + t.skip_ok = True + return t +