xmrwallet, cmdtest xmrwallet: fixes and cleanups

This commit is contained in:
The MMGen Project 2024-04-08 19:00:49 +03:00
commit 524b3515ab
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
5 changed files with 61 additions and 44 deletions

View file

@ -288,7 +288,7 @@ class Signable:
spec = None ),
)
obj = await m.main(f, wallet_idx, restart_daemon=self.need_daemon_restart(m,wallet_idx))
obj.write()
obj.write(quiet=not obj.data.sign)
self.action_desc = 'imported and signed' if obj.data.sign else 'imported'
return obj

View file

@ -13,6 +13,7 @@ help.xmrwallet: xmrwallet help notes for MMGen suite
"""
def help(proto,cfg):
from ..xmrwallet import xmrwallet_uarg_info as uai
return """
Many operations take an optional wallets argument: one or more address
@ -73,7 +74,7 @@ import-key-images - import key images signed by offline wallets into their
This operation takes a LABEL_SPEC arg with the following format:
WALLET:ACCOUNT:ADDRESS,"label text"
{label_spec}
where WALLET is a wallet number, ACCOUNT an account index, and ADDRESS an
address index.
@ -83,40 +84,40 @@ address index.
This operation takes a NEW_ADDRESS_SPEC arg with the following format:
WALLET[:ACCOUNT][,"label text"]
{newaddr_spec}
where WALLET is a wallet number and ACCOUNT an account index. If ACCOUNT is
omitted, a new account will be created in the wallet, otherwise a new address
will be created in the specified account. An optional label text may be
appended to the spec following a comma.
where WALLET is a wallet number and ACCOUNT an account index. If ACCOUNT
is omitted, a new account will be created in the wallet. Otherwise a new
address will be created in the specified account. An optional label text
may be appended to the spec following a comma.
TRANSFER OPERATION NOTES
The transfer operation takes a TRANSFER_SPEC arg with the following format:
SOURCE:ACCOUNT:ADDRESS,AMOUNT
{transfer_spec}
where SOURCE is a wallet number; ACCOUNT the source account index; and ADDRESS
and AMOUNT the destination Monero address and XMR amount, respectively.
where SOURCE is a wallet number, ACCOUNT the source account index, ADDRESS
the destination Monero address and AMOUNT the XMR amount to be sent.
SWEEP OPERATION NOTES
The sweep operation takes a SWEEP_SPEC arg with the following format:
SOURCE:ACCOUNT[,DEST]
{sweep_spec}
where SOURCE and DEST are wallet numbers and ACCOUNT an account index.
If DEST is omitted, a new address will be created in ACCOUNT of SOURCE and
all funds from ACCOUNT of SOURCE will be swept into it.
If DEST is omitted, a new address will be created in ACCOUNT of SOURCE, and
funds from ACCOUNT of SOURCE will be swept into it.
If DEST is included, all funds from ACCOUNT of SOURCE will be swept into a
newly created account in DEST, or the last existing account, if requested
by the user.
The user is prompted before addresses are created or funds are transferred.
The user is prompted before addresses are created or funds transferred.
Note that multiple sweep operations may be required to sweep all the funds
in an account.
@ -386,7 +387,7 @@ Start the cloning process by making dump files of your hot wallets’ metadata
(accounts, subaddresses and labels). cd to the wallet directory (or use
--wallet-dir) and execute:
$ mmgen-xmrwallet dump /path/to/key-address-file.akeys{.mmenc}
$ mmgen-xmrwallet dump /path/to/key-address-file.akeys{{.mmenc}}
If youve been transacting with the wallets, you know where their key-address
file is along with its encryption password, if any. Supply an additional
@ -397,7 +398,7 @@ to ignore.
Do a directory listing to verify that the dump files are present alongside
their source wallet files ending with MoneroWallet. Then execute:
$ mmgen-xmrwallet --watch-only restore /path/to/key-address-file.akeys{.mmenc}
$ mmgen-xmrwallet --watch-only restore /path/to/key-address-file.akeys{{.mmenc}}
This will create watch-only wallets that mirror the old hot wallets and
populate them with the metadata saved in the dump files.
@ -445,4 +446,9 @@ Tutorial above.
Once youve gained proficiency with the autosigning process and feel ready
to delete your old hot wallets, make sure to do so securely using shred,
wipe or some other secure deletion utility.
""".strip()
""".strip().format(
newaddr_spec = uai['newaddr_spec'].annot,
label_spec = uai['label_spec'].annot,
transfer_spec = uai['transfer_spec'].annot,
sweep_spec = uai['sweep_spec'].annot,
)

View file

@ -67,11 +67,11 @@ xmrwallet_uargs = namedtuple('xmrwallet_uargs',[
xmrwallet_uarg_info = (
lambda e,hp: {
'daemon': e('HOST:PORT', hp),
'tx_relay_daemon': e('HOST:PORT[:PROXY_IP:PROXY_PORT]', rf'({hp})(?::({hp}))?'),
'newaddr_spec': e('WALLET_NUM[:ACCOUNT][,"label text"]', r'(\d+)(?::(\d+))?(?:,(.*))?'),
'transfer_spec': e('SOURCE_WALLET_NUM:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{b58a}]+),([0-9.]+)'),
'sweep_spec': e('SOURCE_WALLET_NUM:ACCOUNT[,DEST_WALLET_NUM]', r'(\d+):(\d+)(?:,(\d+))?'),
'label_spec': e('WALLET_NUM:ACCOUNT:ADDRESS,"label text"', r'(\d+):(\d+):(\d+),(.*)'),
'tx_relay_daemon': e('HOST:PORT[:PROXY_IP:PROXY_PORT]', rf'({hp})(?::({hp}))?'),
'newaddr_spec': e('WALLET[:ACCOUNT][,"label text"]', r'(\d+)(?::(\d+))?(?:,(.*))?'),
'transfer_spec': e('SOURCE:ACCOUNT:ADDRESS,AMOUNT', rf'(\d+):(\d+):([{b58a}]+),([0-9.]+)'),
'sweep_spec': e('SOURCE:ACCOUNT[,DEST]', r'(\d+):(\d+)(?:,(\d+))?'),
'label_spec': e('WALLET:ACCOUNT:ADDRESS,"label text"', r'(\d+):(\d+):(\d+),(.*)'),
})(
namedtuple('uarg_info_entry',['annot','pat']),
r'(?:[^:]+):(?:\d+)'
@ -507,7 +507,7 @@ class MoneroWalletOutputsFile:
self.name = type(self).__name__
self.cfg = cfg
def write(self,add_suf=''):
def write(self, add_suf='', quiet=False):
from .fileutil import write_data_to_file
write_data_to_file(
cfg = self.cfg,
@ -515,7 +515,8 @@ class MoneroWalletOutputsFile:
data = self.make_wrapped_data(self.data._asdict()),
desc = self.desc,
ask_overwrite = False,
ignore_opt_outdir = True )
quiet = quiet,
ignore_opt_outdir = True)
def get_outfile(self,cfg,wallet_fn):
return (
@ -1561,21 +1562,26 @@ class MoneroWalletOps:
daemon = wd2 )
def create_tx(self, h, accts_data):
if self.dest is None:
dest_acct = self.account
if keypress_confirm(self.cfg, f'\nCreate new address for account #{self.account}?'):
dest_addr_chk = h.create_new_addr(self.account)
elif keypress_confirm(self.cfg, f'Sweep to last existing address of account #{self.account}?'):
dest_addr_chk = None
else:
def create_new_addr_maybe(h, account, label=None):
if keypress_confirm(self.cfg, f'\nCreate new address for account #{account}?'):
return h.create_new_addr(account, label)
elif not keypress_confirm(self.cfg, f'Sweep to last existing address of account #{account}?'):
die(1,'Exiting at user request')
return None
dest_addr_chk = None
if self.dest is None: # sweep to same account
dest_acct = self.account
dest_addr_chk = create_new_addr_maybe(h, self.account)
dest_addr, dest_addr_idx = h.get_last_addr(self.account, display=not dest_addr_chk)
assert dest_addr_chk in (None, dest_addr), 'dest_addr_chk1'
h.print_addrs(accts_data, self.account)
else:
else: # sweep to wallet
h.close_wallet('source')
h2 = self.rpc(self, self.dest)
h2.open_wallet('destination')
h2.get_accts()
wf = self.get_wallet_fn(self.dest)
if keypress_confirm(self.cfg, f'\nCreate new account for wallet {wf.name!r}?'):
@ -1586,13 +1592,14 @@ class MoneroWalletOps:
elif keypress_confirm(self.cfg, f'Sweep to last existing account of wallet {wf.name!r}?'):
dest_acct, dest_addr_chk = h2.get_last_acct(h2.get_accts()[0])
dest_addr, dest_addr_idx = h2.get_last_addr(dest_acct, display=False)
assert dest_addr_chk == dest_addr, 'dest_addr_chk2'
else:
die(1, 'Exiting at user request')
h2.close_wallet('destination')
h.open_wallet('source', refresh=False)
assert dest_addr_chk in (None, dest_addr), 'dest_addr_chk'
msg(f'\n Creating {self.name} transaction...')
return (h, h.make_sweep_tx(self.account, dest_acct, dest_addr_idx, dest_addr))
@ -1603,6 +1610,11 @@ class MoneroWalletOps:
else:
return f' to new account in wallet {self.dest.idx}'
def check_account_exists(self, accts_data, idx):
max_acct = len(accts_data['subaddress_accounts']) - 1
if self.account > max_acct:
die(2, f'{self.account}: requested account index out of bounds (>{max_acct})')
async def main(self):
gmsg(
@ -1614,9 +1626,7 @@ class MoneroWalletOps:
h.open_wallet('source')
accts_data = h.get_accts()[0]
max_acct = len(accts_data['subaddress_accounts']) - 1
if self.account > max_acct:
die(2, f'{self.account}: requested account index out of bounds (>{max_acct})')
self.check_account_exists(accts_data, self.account)
h.print_addrs(accts_data,self.account)

View file

@ -527,7 +527,7 @@ class CmdTestXMRWallet(CmdTestBase):
tx_relay_parm = None,
no_relay = False,
return_amt = False,
reuse_acct = False,
use_existing = False,
add_opts = [],
add_desc = None,
do_ret = False):
@ -557,12 +557,13 @@ class CmdTestXMRWallet(CmdTestBase):
return t
if op == 'sweep':
desc = 'address' if re.match(r'.*:\d+$', arg2) else 'account'
t.expect(
r'Create new {} .* \(y/N\): '.format(('address','account')[',' in arg2]),
('y','n')[reuse_acct],
rf'Create new {desc} .* \(y/N\): ',
('y','n')[use_existing],
regex=True )
if reuse_acct:
t.expect( r'to last existing account .* \(y/N\): ','y', regex=True )
if use_existing:
t.expect(rf'to last existing {desc} .* \(y/N\): ', 'y', regex=True)
if return_amt:
amt = XMRAmt(strip_ansi_escapes(t.expect_getend('Amount: ')).replace('XMR','').strip())
@ -656,7 +657,7 @@ class CmdTestXMRWallet(CmdTestBase):
send_amt = self.do_op(
'sweep','alice','2:1,3', # '2:1,3'
no_relay = True,
reuse_acct = True,
use_existing = True,
add_desc = f'TX #{i+1}',
return_amt = True )
ok()

View file

@ -28,7 +28,7 @@ class unit_tests:
vs('1:2,3:4', "('1', '2', '3', '4')"),
),
}
vmsg('')
for k,v in uarg_info.items():
vmsg(f' {k}')