From 524b3515ab2801f71631f62ef60c54531df150b3 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 8 Apr 2024 19:00:49 +0300 Subject: [PATCH] xmrwallet, cmdtest xmrwallet: fixes and cleanups --- mmgen/autosign.py | 2 +- mmgen/help/xmrwallet.py | 38 +++++++++++++---------- mmgen/xmrwallet.py | 50 ++++++++++++++++++------------- test/cmdtest_py_d/ct_xmrwallet.py | 13 ++++---- test/unit_tests_d/ut_misc.py | 2 +- 5 files changed, 61 insertions(+), 44 deletions(-) diff --git a/mmgen/autosign.py b/mmgen/autosign.py index c30e3088..45d466c5 100755 --- a/mmgen/autosign.py +++ b/mmgen/autosign.py @@ -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 diff --git a/mmgen/help/xmrwallet.py b/mmgen/help/xmrwallet.py index d4216c7b..6a110b4d 100755 --- a/mmgen/help/xmrwallet.py +++ b/mmgen/help/xmrwallet.py @@ -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 you’ve 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 you’ve 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, +) diff --git a/mmgen/xmrwallet.py b/mmgen/xmrwallet.py index 1b56c734..f0e0e8cc 100755 --- a/mmgen/xmrwallet.py +++ b/mmgen/xmrwallet.py @@ -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) diff --git a/test/cmdtest_py_d/ct_xmrwallet.py b/test/cmdtest_py_d/ct_xmrwallet.py index ebbe3322..daac1f60 100755 --- a/test/cmdtest_py_d/ct_xmrwallet.py +++ b/test/cmdtest_py_d/ct_xmrwallet.py @@ -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() diff --git a/test/unit_tests_d/ut_misc.py b/test/unit_tests_d/ut_misc.py index 2ef3d1d8..fceeddd0 100755 --- a/test/unit_tests_d/ut_misc.py +++ b/test/unit_tests_d/ut_misc.py @@ -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}')