mmgen-xmrwallet: new view and listview operations
- view:
display a summary of accounts and balances in offline mode. May be
invoked without a running monerod
- listview:
same as ‘view’, but also list detailed address info for accounts
This commit is contained in:
parent
1f75be898d
commit
0de5e47c3c
5 changed files with 66 additions and 13 deletions
|
|
@ -37,7 +37,11 @@ plain HTTP is not supported.
|
|||
|
||||
create - create wallets for all or specified addresses in key-address file
|
||||
sync - sync wallets for all or specified addresses in key-address file
|
||||
and display a summary of accounts and balances
|
||||
list - same as ‘sync’, but also list detailed address info for accounts
|
||||
view - display a summary of accounts and balances in offline mode. May
|
||||
be invoked without a running monerod
|
||||
listview - same as ‘view’, but also list detailed address info for accounts
|
||||
label - set a label for an address
|
||||
new - create a new account in a wallet, or a new address in an account
|
||||
transfer - transfer specified XMR amount from specified wallet:account to
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ opts_data = {
|
|||
'desc': """Perform various Monero wallet and transacting operations for
|
||||
addresses in an MMGen XMR key-address file""",
|
||||
'usage2': [
|
||||
'[opts] create | sync | list | dump | restore [xmr_keyaddrfile] [wallets]',
|
||||
'[opts] create | sync | list | view | listview | dump | restore [xmr_keyaddrfile] [wallets]',
|
||||
'[opts] label [xmr_keyaddrfile] LABEL_SPEC',
|
||||
'[opts] new [xmr_keyaddrfile] NEW_ADDRESS_SPEC',
|
||||
'[opts] transfer [xmr_keyaddrfile] TRANSFER_SPEC',
|
||||
|
|
@ -126,7 +126,7 @@ if op in ('relay','submit','resubmit'):
|
|||
cfg._opts.usage()
|
||||
elif op in ('txview','txlist'):
|
||||
infile = [infile] + cmd_args
|
||||
elif op in ('create','sync','list','dump','restore'): # kafile_arg_ops
|
||||
elif op in ('create','sync','list','view','listview','dump','restore'): # kafile_arg_ops
|
||||
if len(cmd_args) > 1:
|
||||
cfg._opts.usage()
|
||||
wallets = cmd_args.pop(0) if cmd_args else None
|
||||
|
|
|
|||
|
|
@ -605,6 +605,8 @@ class MoneroWalletOps:
|
|||
'create_offline',
|
||||
'sync',
|
||||
'list',
|
||||
'view',
|
||||
'listview',
|
||||
'new',
|
||||
'transfer',
|
||||
'sweep',
|
||||
|
|
@ -624,6 +626,8 @@ class MoneroWalletOps:
|
|||
'create',
|
||||
'sync',
|
||||
'list',
|
||||
'view',
|
||||
'listview',
|
||||
'label',
|
||||
'new',
|
||||
'transfer',
|
||||
|
|
@ -686,6 +690,8 @@ class MoneroWalletOps:
|
|||
|
||||
self.proto = init_proto( cfg, 'xmr', network=self.cfg.network, need_amt=True )
|
||||
|
||||
self.pre_init_action()
|
||||
|
||||
def check_uopts(self):
|
||||
|
||||
def check_pat_opt(name):
|
||||
|
|
@ -722,6 +728,9 @@ class MoneroWalletOps:
|
|||
Proxy: {blue(m[2] or 'None')}
|
||||
""",strip_char='\t',indent=indent))
|
||||
|
||||
def pre_init_action(self):
|
||||
pass
|
||||
|
||||
def post_main_success(self):
|
||||
pass
|
||||
|
||||
|
|
@ -1298,7 +1307,8 @@ class MoneroWalletOps:
|
|||
|
||||
super().__init__(cfg,uarg_tuple)
|
||||
|
||||
self.dc = self.get_coin_daemon_rpc()
|
||||
if not self.wallet_offline:
|
||||
self.dc = self.get_coin_daemon_rpc()
|
||||
|
||||
self.accts_data = {}
|
||||
|
||||
|
|
@ -1368,9 +1378,9 @@ class MoneroWalletOps:
|
|||
d = self.accts_data
|
||||
|
||||
for wnum,k in enumerate(d):
|
||||
if self.name == 'sync':
|
||||
if self.name in ('sync','view'):
|
||||
self.rpc(self,self.addr_data[wnum]).print_accts( d[k]['accts'], d[k]['addrs'], indent='')
|
||||
elif self.name == 'list':
|
||||
elif self.name in ('list','listview'):
|
||||
fs = ' {:2} {} {} {}'
|
||||
msg('\n' + green(f'Wallet {k}:'))
|
||||
for acct_num,acct in enumerate(d[k]['addrs']):
|
||||
|
|
@ -1407,6 +1417,34 @@ class MoneroWalletOps:
|
|||
class list(sync):
|
||||
stem = 'sync'
|
||||
|
||||
class view(sync):
|
||||
stem = 'open'
|
||||
opts = ()
|
||||
wallet_offline = True
|
||||
|
||||
def pre_init_action(self):
|
||||
ymsg('WARNING: Running in offline mode. Balances and other info may be out of date!')
|
||||
|
||||
async def process_wallet(self,d,fn,last):
|
||||
|
||||
self.c.call(
|
||||
'open_wallet',
|
||||
filename = fn.name,
|
||||
password = d.wallet_passwd)
|
||||
|
||||
wallet_height = self.c.call('get_height')['height']
|
||||
msg(f' Wallet height: {wallet_height}')
|
||||
a,b = self.rpc(self, d).get_accts(print=False)
|
||||
self.accts_data[fn.name] = {'accts': a, 'addrs': b}
|
||||
|
||||
if not last:
|
||||
self.c.call('close_wallet')
|
||||
|
||||
return True
|
||||
|
||||
class listview(view):
|
||||
pass
|
||||
|
||||
class spec(wallet): # virtual class
|
||||
|
||||
def create_addr_data(self):
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignBase):
|
|||
('check_tx_dirs', 'cleaning and checking signable file directories'),
|
||||
('autosign_kill_thread', 'stopping autosign wait loop'),
|
||||
('stop_daemons', 'stopping all wallet and coin daemons'),
|
||||
('view', 'viewing Alice’s wallet in offline mode (wallet #1)'),
|
||||
('listview', 'list-viewing Alice’s wallet in offline mode (wallet #2)'),
|
||||
)
|
||||
|
||||
def __init__(self,trunner,cfgs,spawn):
|
||||
|
|
@ -488,3 +490,9 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignBase):
|
|||
pat = r'xmr/tx: \s*\S+\.subtx \S+\.subtx\s+xmr/outputs:\s*$'
|
||||
assert re.search( pat, after, re.DOTALL ), f'regex search for {pat} failed'
|
||||
return t
|
||||
|
||||
def view(self):
|
||||
return self.sync_wallets('alice', op='view', wallets='1')
|
||||
|
||||
def listview(self):
|
||||
return self.sync_wallets('alice', op='listview', wallets='2')
|
||||
|
|
|
|||
|
|
@ -500,18 +500,21 @@ class CmdTestXMRWallet(CmdTestBase):
|
|||
)
|
||||
wlist = AddrIdxList(wallets) if wallets else MMGenRange(data.kal_range).items
|
||||
for n,wnum in enumerate(wlist,1):
|
||||
t.expect('Syncing wallet {}/{} ({})'.format(
|
||||
t.expect('ing wallet {}/{} ({})'.format(
|
||||
n,
|
||||
len(wlist),
|
||||
os.path.basename(data.walletfile_fs.format(wnum)),
|
||||
))
|
||||
t.expect('Chain height: ')
|
||||
t.expect('Wallet height: ')
|
||||
res = strip_ansi_escapes(t.expect_getend('Balance: '))
|
||||
if bal_chk_func:
|
||||
m = re.match( r'(\S+) Unlocked balance: (\S+)', res, re.DOTALL )
|
||||
amts = [XMRAmt(amt) for amt in m.groups()]
|
||||
assert bal_chk_func(n,*amts), f'balance check for wallet {n} failed!'
|
||||
if op in ('view','listview'):
|
||||
t.expect('Wallet height: ')
|
||||
else:
|
||||
t.expect('Chain height: ')
|
||||
t.expect('Wallet height: ')
|
||||
res = strip_ansi_escapes(t.expect_getend('Balance: '))
|
||||
if bal_chk_func:
|
||||
m = re.match( r'(\S+) Unlocked balance: (\S+)', res, re.DOTALL )
|
||||
amts = [XMRAmt(amt) for amt in m.groups()]
|
||||
assert bal_chk_func(n,*amts), f'balance check for wallet {n} failed!'
|
||||
return t
|
||||
|
||||
def do_op(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue