Browse Source

xmrwallet, cmdtest xmrwallet: fixes and cleanups

The MMGen Project 1 year ago
parent
commit
524b3515ab
5 changed files with 61 additions and 44 deletions
  1. 1 1
      mmgen/autosign.py
  2. 22 16
      mmgen/help/xmrwallet.py
  3. 30 20
      mmgen/xmrwallet.py
  4. 7 6
      test/cmdtest_py_d/ct_xmrwallet.py
  5. 1 1
      test/unit_tests_d/ut_misc.py

+ 1 - 1
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
 

+ 22 - 16
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,
+)

+ 30 - 20
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)
 

+ 7 - 6
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()

+ 1 - 1
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}')