From d9b344d1f538ddea8a94b8277f44db8a3da23578 Mon Sep 17 00:00:00 2001 From: MMGen Date: Sat, 13 Oct 2018 15:00:03 +0000 Subject: [PATCH] eth: listaddresses, twview display fixes; add tests - remove confirmations and days columns in address lists for eth --- mmgen/altcoins/eth/tw.py | 4 +- mmgen/common.py | 4 +- mmgen/tw.py | 13 +-- test/test.py | 187 +++++++++++++++++++++++++++++---------- 4 files changed, 152 insertions(+), 56 deletions(-) diff --git a/mmgen/altcoins/eth/tw.py b/mmgen/altcoins/eth/tw.py index 1656680d..29a7b2fa 100755 --- a/mmgen/altcoins/eth/tw.py +++ b/mmgen/altcoins/eth/tw.py @@ -224,7 +224,7 @@ class EthereumTwAddrList(TwAddrList): from mmgen.obj import CoinAddr for mmid,d in tw.items(): -# if d['confirmations'] < minconf: continue +# if d['confirmations'] < minconf: continue # cannot get confirmations for eth account label = TwLabel(mmid+' '+d['comment'],on_fail='raise') if usr_addr_list and (label.mmid not in usr_addr_list): continue bal = self.get_addr_balance(d['addr']) @@ -234,7 +234,7 @@ class EthereumTwAddrList(TwAddrList): self[label.mmid] = {'amt': g.proto.coin_amt('0'), 'lbl': label } if showbtcaddrs: self[label.mmid]['addr'] = CoinAddr(d['addr']) - self[label.mmid]['lbl'].mmid.confs = 9999 # TODO + self[label.mmid]['lbl'].mmid.confs = None self[label.mmid]['amt'] += bal self.total += bal diff --git a/mmgen/common.py b/mmgen/common.py index 5ec9d049..8d2ad705 100755 --- a/mmgen/common.py +++ b/mmgen/common.py @@ -48,8 +48,8 @@ def help_notes(k): 'rel_fee_desc': MMGenTX().rel_fee_desc, 'fee_spec_letters': fee_spec_letters(), 'passwd': """ -For passphrases all combinations of whitespace are equal and leading and -trailing space is ignored. This permits reading passphrase or brainwallet +For passphrases all combinations of whitespace are equal, and leading and +trailing space are ignored. This permits reading passphrase or brainwallet data from a multi-line file with free spacing and indentation. """.strip(), 'brainwallet': """ diff --git a/mmgen/tw.py b/mmgen/tw.py index e88752ef..700dc675 100755 --- a/mmgen/tw.py +++ b/mmgen/tw.py @@ -232,8 +232,8 @@ watch-only wallet using '{}-addrimport' and then re-run this program. mmid_w = max(len(('',i.twmmid)[i.twmmid.type=='mmgen']) for i in self.unspent) or 12 # DEADBEEF:S:1 amt_w = g.proto.coin_amt.max_prec + 4 fs = { 'btc': u' {n:4} {t:%s} {a} {m} {A:%s} {c:<8} {g:<6} {l}' % (self.txid_w+3,amt_w), - 'eth': u' {n:4} {a} {m} {A:%s} {c:<8} {g:<6} {l}' % amt_w, - 'token': u' {n:4} {a} {m} {A:%s} {A2:%s} {c:<8} {g:<6} {l}' % (amt_w,amt_w) + 'eth': u' {n:4} {a} {m} {A:%s} {l}' % amt_w, + 'token': u' {n:4} {a} {m} {A:%s} {A2:%s} {l}' % (amt_w,amt_w) }[self.disp_type] out = [fs.format( n='Num', t='Tx ID,Vout', @@ -241,8 +241,8 @@ watch-only wallet using '{}-addrimport' and then re-run this program. m='MMGen ID'.ljust(mmid_w+1), A='Amount({})'.format(g.dcoin).ljust(amt_w+1), A2='Amount({})'.format(g.coin), - c='Confs', - g='Age(d)', + c='Confs', # skipped for eth + g='Age(d)', # skipped for eth l='Label')] max_lbl_len = max([len(i.label) for i in self.unspent if i.label] or [2]) @@ -445,7 +445,8 @@ class TwAddrList(MMGenDict): if sort and 'age' in sort: return '{}_{:>012}_{}'.format( j.obj.rsplit(':',1)[0], - (1000000000-j.confs if hasattr(j,'confs') else 0), # Hack, but OK for the foreseeable future + # Hack, but OK for the foreseeable future: + (1000000000-j.confs if hasattr(j,'confs') and j.confs != None else 0), j.sort_key) else: return j.sort_key @@ -469,7 +470,7 @@ class TwAddrList(MMGenDict): addr=(e['addr'].fmt(color=True,width=addr_width) if showbtcaddrs else None), cmt=e['lbl'].comment.fmt(width=max_cmt_len,color=True,nullrepl='-'), amt=e['amt'].fmt('4.{}'.format(max(max_fp_len,3)),color=True), - age=mmid.confs / (1,confs_per_day)[show_days] if hasattr(mmid,'confs') else '-' + age=mmid.confs / (1,confs_per_day)[show_days] if hasattr(mmid,'confs') and mmid.confs != None else '-' )) return '\n'.join(out + ['\nTOTAL: {} {}'.format(self.total.hl(color=True),g.dcoin)]) diff --git a/test/test.py b/test/test.py index 0e43c7df..f2095822 100755 --- a/test/test.py +++ b/test/test.py @@ -121,34 +121,35 @@ opts_data = lambda: { 'desc': 'Test suite for the MMGen suite', 'usage':'[options] [command(s) or metacommand(s)]', 'options': """ --h, --help Print this help message ---, --longhelp Print help message for long options (common options) --B, --bech32 Generate and use Bech32 addresses --b, --buf-keypress Use buffered keypresses as with real human input --c, --print-cmdline Print the command line of each spawned command --C, --coverage Produce code coverage info using trace module --x, --debug-pexpect Produce debugging output for pexpect calls --D, --direct-exec Bypass pexpect and execute a command directly (for - debugging only) --e, --exact-output Show the exact output of the MMGen script(s) being run --g, --segwit Generate and use Segwit addresses --G, --segwit-random Generate and use a random mix of Segwit and Legacy addrs --l, --list-cmds List and describe the commands in the test suite --L, --log Log commands to file {lf} --n, --names Display command names instead of descriptions --O, --popen-spawn Use pexpect's popen_spawn instead of popen (always true, so ignored) --p, --pause Pause between tests, resuming on keypress --P, --profile Record the execution time of each script --q, --quiet Produce minimal output. Suppress dependency info --r, --resume=c Resume at command 'c' after interrupted run --s, --system Test scripts and modules installed on system rather - than those in the repo root --S, --skip-deps Skip dependency checking for command --u, --usr-random Get random data interactively from user --t, --traceback Run the command inside the '{tbc}' script --v, --verbose Produce more verbose output --W, --no-dw-delete Don't remove default wallet from data dir after dw tests are done --X, --exit-after=C Exit after command 'C' +-h, --help Print this help message +--, --longhelp Print help message for long options (common options) +-B, --bech32 Generate and use Bech32 addresses +-b, --buf-keypress Use buffered keypresses as with real human input +-c, --print-cmdline Print the command line of each spawned command +-C, --coverage Produce code coverage info using trace module +-x, --debug-pexpect Produce debugging output for pexpect calls +-D, --no-daemon-stop Don't stop auto-started daemons after running tests +-E, --direct-exec Bypass pexpect and execute a command directly (for + debugging only) +-e, --exact-output Show the exact output of the MMGen script(s) being run +-g, --segwit Generate and use Segwit addresses +-G, --segwit-random Generate and use a random mix of Segwit and Legacy addrs +-l, --list-cmds List and describe the commands in the test suite +-L, --log Log commands to file {lf} +-n, --names Display command names instead of descriptions +-O, --popen-spawn Use pexpect's popen_spawn instead of popen (always true, so ignored) +-p, --pause Pause between tests, resuming on keypress +-P, --profile Record the execution time of each script +-q, --quiet Produce minimal output. Suppress dependency info +-r, --resume=c Resume at command 'c' after interrupted run +-s, --system Test scripts and modules installed on system rather + than those in the repo root +-S, --skip-deps Skip dependency checking for command +-u, --usr-random Get random data interactively from user +-t, --traceback Run the command inside the '{tbc}' script +-v, --verbose Produce more verbose output +-W, --no-dw-delete Don't remove default wallet from data dir after dw tests are done +-X, --exit-after=C Exit after command 'C' """.format(tbc=g.traceback_cmd,lf=log_file), 'notes': """ @@ -807,6 +808,12 @@ cmd_group['regtest'] = ( ('regtest_bob_split1', "splitting Bob's funds"), ('regtest_generate', 'mining a block'), ('regtest_bob_bal2', "Bob's balance"), + ('regtest_bob_bal2a', "Bob's balance (show_days=1)"), + ('regtest_bob_bal2b', "Bob's balance (show_age=1)"), + ('regtest_bob_bal2c', "Bob's balance (showempty=1 show_age=1 minconf=2)"), + ('regtest_bob_bal2d', "Bob's balance (show_age=1 minconf=2)"), + ('regtest_bob_bal2e', "Bob's balance (showempty=1 show_age=1 sort=age)"), + ('regtest_bob_bal2f', "Bob's balance (showempty=1 show_age=1 sort=age,reverse)"), ('regtest_bob_rbf_send', 'sending funds to Alice (RBF)'), ('regtest_get_mempool1', 'mempool (before RBF bump)'), ('regtest_bob_rbf_bump', 'bumping RBF transaction'), @@ -841,7 +848,7 @@ cmd_group['regtest'] = ( ('regtest_alice_add_label_rpcfail','RPC failure code'), ('regtest_alice_send_estimatefee','tx creation with no fee on command line'), ('regtest_generate', 'mining a block'), - ('regtest_bob_bal6', "Bob's balance"), + ('regtest_bob_bal6', "Bob's balance"), ('regtest_bob_alice_bal', "Bob and Alice's balances"), ('regtest_alice_bal2', "Alice's balance"), ('regtest_stop', 'stopping regtest daemon'), @@ -934,7 +941,7 @@ cmd_group['ethdev'] = ( ('ethdev_token_txsign1', 'signing the transaction'), ('ethdev_token_txsend1', 'sending the transaction'), - ('ethdev_token_twview1', 'viewing token tracking wallet'), + ('ethdev_token_twview1_chk', 'viewing token tracking wallet'), ('ethdev_token_txcreate2', 'creating a token transaction (to burn address)'), ('ethdev_token_txbump', 'bumping the transaction fee'), @@ -965,7 +972,26 @@ cmd_group['ethdev'] = ( ('ethdev_token_bal3', 'the token balance'), -# ('ethdev_stop', 'stopping parity'), + ('ethdev_listaddresses1', 'listaddresses'), + ('ethdev_listaddresses2', 'listaddresses minconf=999999999 (ignored)'), + ('ethdev_listaddresses3', 'listaddresses sort=age (ignored)'), + ('ethdev_listaddresses4', 'listaddresses showempty=1 sort=age (ignored)'), + + ('ethdev_token_listaddresses1','listaddresses --token=mm1'), + ('ethdev_token_listaddresses2','listaddresses --token=mm1 showempty=1'), + + ('ethdev_twview1','twview'), + ('ethdev_twview2','twview wide=1'), + ('ethdev_twview3','twview wide=1 sort=age (ignored)'), + ('ethdev_twview4','twview wide=1 minconf=999999999 (ignored)'), + ('ethdev_twview5','twview wide=1 minconf=0 (ignored)'), + ('ethdev_twview6','twview show_days=0 (ignored)'), + + ('ethdev_token_twview1','twview --token=mm1'), + ('ethdev_token_twview2','twview --token=mm1 wide=1'), + ('ethdev_token_twview3','twview --token=mm1 wide=1 sort=age (ignored)'), + + ('ethdev_stop', 'stopping parity'), ) cmd_group['autosign'] = ( @@ -2765,10 +2791,14 @@ class MMGenTestSuite(object): def regtest_fund_bob(self,name): self.regtest_fund_wallet(name,'bob','C',rtFundAmt) def regtest_fund_alice(self,name): self.regtest_fund_wallet(name,'alice',('L','S')[g.proto.cap('segwit')],rtFundAmt) - def regtest_user_bal(self,name,user,bal): - t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses','showempty=1']) - total = t.expect_getend('TOTAL: ') - cmp_or_die('{} {}'.format(bal,g.coin),total) + def regtest_user_bal(self,name,user,bal,args=['showempty=1'],skip_check=False,exit_val=0): + t = MMGenExpect(name,'mmgen-tool',['--'+user,'listaddresses'] + args) + if skip_check: + t.read() + t.ok(exit_val=exit_val) + else: + total = t.expect_getend('TOTAL: ') + cmp_or_die('{} {}'.format(bal,g.coin),total) def regtest_alice_bal1(self,name): return self.regtest_user_bal(name,'alice',rtFundAmt) @@ -2782,6 +2812,24 @@ class MMGenTestSuite(object): def regtest_bob_bal2(self,name): return self.regtest_user_bal(name,'bob',rtBals[0]) + def regtest_bob_bal2a(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['showempty=1','show_days=1']) + + def regtest_bob_bal2b(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['showempty=1','show_age=1']) + + def regtest_bob_bal2c(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['showempty=1','show_age=1','minconf=2'],skip_check=True) + + def regtest_bob_bal2d(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['show_age=1','minconf=2'],skip_check=True) + + def regtest_bob_bal2e(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['showempty=1','show_age=1','sort=age']) + + def regtest_bob_bal2f(self,name): + return self.regtest_user_bal(name,'bob',rtBals[0],args=['showempty=1','show_age=1','sort=age,reverse']) + def regtest_bob_bal3(self,name): return self.regtest_user_bal(name,'bob',rtBals[1]) @@ -3086,8 +3134,13 @@ class MMGenTestSuite(object): t.ok() def regtest_stop(self,name): - t = MMGenExpect(name,'mmgen-regtest',['stop']) - t.ok() + if opt.no_daemon_stop: + MMGenExpect(name,'',msg_only=True) + msg_r('(leaving daemon running by user request)') + ok() + else: + t = MMGenExpect(name,'mmgen-regtest',['stop']) + t.ok() def regtest_split_setup(self,name): if g.coin != 'BTC': die(1,'Test valid only for coin BTC') @@ -3453,14 +3506,15 @@ class MMGenTestSuite(object): def ethdev_token_txsend1(self,name): self.ethdev_token_txsend(name,ext='1.23456,50000].sigtx',token='mm1') - def ethdev_twview(self,name,args,expect_str): - t = MMGenExpect(name,'mmgen-tool', eth_args() + args + ['twview']) - t.expect(expect_str,regex=True) + def ethdev_twview(self,name,args=[],expect_str='',tool_args=[],exit_val=0): + t = MMGenExpect(name,'mmgen-tool', eth_args() + args + ['twview'] + tool_args) + if expect_str: + t.expect(expect_str,regex=True) t.read() - t.ok() + t.ok(exit_val=exit_val) - bal_corr = Decimal('0.0000032') # gas use varies for token sends! - def ethdev_token_twview1(self,name): + bal_corr = Decimal('0.0000032') # gas use for token sends varies between ETH and ETC! + def ethdev_token_twview1_chk(self,name): ebal = Decimal('1.2314236') if g.coin == 'ETC': ebal += self.bal_corr s = '98831F3A:E:11\s+998.76544\s+' + str(ebal) @@ -3529,11 +3583,52 @@ class MMGenTestSuite(object): def ethdev_token_bal3(self,name): self.ethdev_token_bal(name,expect_str=r'98831F3A:E:13\s+1.23456\s') + def ethdev_listaddresses(self,name,args=[],tool_args=['all_labels=1'],exit_val=0): + t = MMGenExpect(name,'mmgen-tool', eth_args() + args + ['listaddresses'] + tool_args) + t.read() + t.ok(exit_val=exit_val) + + def ethdev_listaddresses1(self,name): + return self.ethdev_listaddresses(name) + def ethdev_listaddresses2(self,name): + return self.ethdev_listaddresses(name,tool_args=['minconf=999999999']) + def ethdev_listaddresses3(self,name): + return self.ethdev_listaddresses(name,tool_args=['sort=age']) + def ethdev_listaddresses4(self,name): + return self.ethdev_listaddresses(name,tool_args=['sort=age','showempty=1']) + + def ethdev_token_listaddresses1(self,name): + return self.ethdev_listaddresses(name,args=['--token=mm1']) + def ethdev_token_listaddresses2(self,name): + return self.ethdev_listaddresses(name,args=['--token=mm1'],tool_args=['showempty=1']) + + def ethdev_twview1(self,name): + return self.ethdev_twview(name) + def ethdev_twview2(self,name): + return self.ethdev_twview(name,tool_args=['wide=1']) + def ethdev_twview3(self,name): + return self.ethdev_twview(name,tool_args=['wide=1','sort=age']) + def ethdev_twview4(self,name): + return self.ethdev_twview(name,tool_args=['wide=1','minconf=999999999']) + def ethdev_twview5(self,name): + return self.ethdev_twview(name,tool_args=['wide=1','minconf=0']) + def ethdev_twview6(self,name): + return self.ethdev_twview(name,tool_args=['show_days=0']) + + def ethdev_token_twview1(self,name): + return self.ethdev_twview(name,args=['--token=mm1']) + def ethdev_token_twview2(self,name): + return self.ethdev_twview(name,args=['--token=mm1'],tool_args=['wide=1']) + def ethdev_token_twview3(self,name): + return self.ethdev_twview(name,args=['--token=mm1'],tool_args=['wide=1','sort=age']) + def ethdev_stop(self,name): MMGenExpect(name,'',msg_only=True) - pid = read_from_tmpfile(cfg,cfg['parity_pidfile']) - assert pid,'No parity pid file!' - subprocess.check_call(['kill',pid]) + pid = read_from_tmpfile(cfg,cfg['parity_pidfile']) # exits if file not found + if opt.no_daemon_stop: + msg_r('(leaving daemon running by user request)') + else: + subprocess.check_call(['kill',pid]) ok() # undocumented admin commands