4 Commits 48edcf412c ... 4a4b814935

Author SHA1 Message Date
  The MMGen Project 4a4b814935 XMR compat: export outputs files during TX creation 2 months ago
  The MMGen Project 0c4438a35d xmrwallet.ops.sweep: `check_account_exists()`: bugfix 2 months ago
  The MMGen Project 80d122a1d8 XMR compat: allow sweep transaction to empty account (bugfix) 2 months ago
  The MMGen Project 58fc466e13 proto.xmr.tw.view: remove `self.dump_data` attribute 2 months ago

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-16.1.dev29
+16.1.dev30

+ 1 - 1
mmgen/proto/xmr/tw/unspent.py

@@ -20,7 +20,6 @@ class MoneroTwUnspentOutputs(MoneroTwView, TwUnspentOutputs):
 
 	hdr_lbl = 'spendable accounts'
 	desc = 'spendable accounts'
-	include_empty = False
 
 	async def __init__(self, cfg, proto, *, minconf=1, addrs=[], tx=None):
 		self.prompt_fs_in = [
@@ -38,6 +37,7 @@ class MoneroTwUnspentOutputs(MoneroTwView, TwUnspentOutputs):
 				's': 'i_addr_sweep',
 				'S': 'i_acct_sweep'})
 		await super().__init__(cfg, proto, minconf=minconf, addrs=addrs, tx=tx)
+		self.is_sweep = self.include_empty = self.tx and self.tx.is_sweep
 
 	async def get_idx_from_user(self, method_name):
 		if method_name in ('i_acct_sweep', 'i_addr_sweep'):

+ 17 - 8
mmgen/proto/xmr/tw/view.py

@@ -29,6 +29,7 @@ class MoneroTwView:
 	item_desc = 'account'
 	nice_addr_w = {'addr': 20}
 	total = None
+	is_sweep = False
 
 	sort_disp = {
 		'addr':   'Addr',
@@ -57,16 +58,16 @@ class MoneroTwView:
 
 		op = xmrwallet_op('dump_data', self.cfg, None, None, compat_call=True)
 		await op.restart_wallet_daemon()
-		self.dump_data = await op.main()
+		dump_data = await op.main()
 
-		if self.dump_data:
-			self.sid = SeedID(sid=self.dump_data[0]['seed_id'])
+		if dump_data:
+			self.sid = SeedID(sid=dump_data[0]['seed_id'])
 
 		self.total = self.unlocked_total = self.proto.coin_amt('0')
 
 		def gen_addrs():
 			bd = namedtuple('address_balance_data', ['bal', 'unlocked_bal', 'blocks_to_unlock'])
-			for wdata in self.dump_data:
+			for wdata in dump_data:
 				bals_data = {i: {} for i in range(len(wdata['data'].accts_data['subaddress_accounts']))}
 
 				for d in wdata['data'].bals_data.get('per_subaddress', []):
@@ -195,8 +196,14 @@ class MoneroTwView:
 					color = color,
 					color_override = None if d.total == d.unlocked_total else 'orange'
 				)) + rfill
-			for v in d.data.values():
-				yield fmt_method(None, v.data, cw, fs, color, yes, no)
+			if self.is_sweep:
+				if d.total:
+					for v in d.data.values():
+						if v.data.amt:
+							yield fmt_method(None, v.data, cw, fs, color, yes, no)
+			else:
+				for v in d.data.values():
+					yield fmt_method(None, v.data, cw, fs, color, yes, no)
 
 	def squeezed_format_line(self, n, d, cw, fs, color, yes, no):
 		return fs.format(
@@ -235,12 +242,14 @@ class MoneroTwView:
 		from ....obj import Int
 		from ....util import msg, suf
 		from ....ui import item_chooser
+		wdata = {}
+		for d in self.accts_data:
+			wdata[d.idx] = (wdata[d.idx] + 1) if d.idx in wdata else 1
 		msg('\n')
 		return item_chooser(
 			self.cfg,
 			prompt,
-			[(d['wallet_num'], len(d['data'].accts_data['subaddress_accounts']))
-				for d in self.dump_data],
+			tuple(wdata.items()),
 			lambda d: '{a} [{b} account{c}]'.format(
 				a = self.make_wallet_id(d[0]).hl(),
 				b = Int(d[1]).hl(),

+ 10 - 0
mmgen/proto/xmr/tx/new.py

@@ -76,4 +76,14 @@ class New(Base, TxNew):
 			compat_call = True)
 
 		await op.restart_wallet_daemon()
+
+		if idxs := op.get_idxs_for_missing_outputs_files():
+			op2 = xmrwallet_op(
+				'export_outputs',
+				self.cfg,
+				None,
+				','.join(map(str, idxs)),
+				compat_call = True)
+			await op2.main()
+
 		return await op.main()

+ 17 - 2
mmgen/xmrwallet/ops/sweep.py

@@ -165,8 +165,23 @@ class OpSweep(OpMixinSpec, OpWallet):
 
 	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})')
+		if idx > max_acct:
+			die(2, f'{idx}: requested account index out of bounds (>{max_acct})')
+
+	def get_idxs_for_missing_outputs_files(self):
+		from ..file.outputs import MoneroWalletOutputsFile
+		def gen():
+			d_old = None
+			for k in ('source', 'dest'):
+				d = getattr(self, k, None)
+				if d and d != d_old:
+					d_old = d
+					if not MoneroWalletOutputsFile.Unsigned.find_fn_from_wallet_fn(
+							cfg             = self.cfg,
+							wallet_fn       = self.get_wallet_fn(d),
+							ret_on_no_match = True):
+						yield(d.idx)
+		return tuple(gen())
 
 	async def main(self):
 		gmsg(

+ 1 - 1
test/cmdtest_d/autosign.py

@@ -189,7 +189,7 @@ class CmdTestAutosignBase(CmdTestBase):
 		stop_test_daemons(*(self.network_ids + self.extra_daemons), remove_datadir=True)
 		return 'ok'
 
-	def delete_setup(self):
+	def delete_offline_shmdir(self):
 		self.spawn(msg_only=True)
 		imsg(f'Deleting ‘{self.asi.wallet_dir}’')
 		shutil.rmtree(self.asi.wallet_dir, ignore_errors=True)

+ 17 - 5
test/cmdtest_d/xmr_autosign.py

@@ -520,9 +520,6 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 	cmd_group = (
 		('autosign_setup',           'autosign setup with Alice’s seed'),
 		('autosign_xmr_setup',       'autosign setup (creation of Monero signing wallets)'),
-		('delete_setup',             'deleting offline autosign setup'),
-		('autosign_setup',           'autosign setup with Alice’s seed'),
-		('autosign_xmr_setup_redo',  'autosign setup (creation of Monero signing wallets, redo)'),
 		('create_watchonly_wallets', 'creating Alice’s watch-only wallets'),
 		('gen_kafile_miner',         'generating key-address file for Miner'),
 		('create_wallet_miner',      'creating Monero wallet for Miner'),
@@ -571,6 +568,15 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 		('mine_blocks_10',           'mining some blocks'),
 		('alice_twview_chk4',        'viewing Alice’s tracking wallets (check balances)'),
 		('wait_loop_kill',           'stopping autosign wait loop'),
+		('delete_offline_shmdir',    'deleting offline autosign wallet dir'),
+		('autosign_setup',           'autosign setup with Alice’s seed'),
+		('autosign_xmr_setup_redo',  'autosign setup (creation of Monero signing wallets, redo)'),
+		('wait_loop_start_compat',   'starting autosign wait loop in XMR compat mode [--coins=xmr]'),
+		('alice_txcreate_sweep3',    'creating a sweep transaction (sweep to empty account)'),
+		('alice_txsend4',            'sending the transaction'),
+		('mine_blocks_10',           'mining some blocks'),
+		('alice_twview_chk5',        'viewing Alice’s tracking wallets (check balances)'),
+		('wait_loop_kill',           'stopping autosign wait loop'),
 		('alice_newacct1',           'adding account to Alice’s tracking wallet (dfl label)'),
 		('alice_newacct2',           'adding account to Alice’s tracking wallet (no timestr)'),
 		('alice_newacct3',           'adding account to Alice’s tracking wallet'),
@@ -717,6 +723,9 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 	def alice_twview_chk4(self):
 		return self._alice_twview_chk(['Total XMR: 3.709050970119', '1.254861787651'], sync=True)
 
+	def alice_twview_chk5(self):
+		return self._alice_twview_chk(['Total XMR: 3.707234170119', '2.452375982468'], sync=True)
+
 	def _alice_twview_chk(self, expect_arr, sync=False):
 		return self._alice_twops(
 			'twview',
@@ -791,7 +800,10 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 		return self._alice_txops('txcreate', menu='S', sweep_menu='23', sweep_type='sweep')
 
 	def alice_txcreate_sweep2(self):
-		return self._alice_txops('txcreate', menu='s', sweep_menu='2', sweep_type='sweep_all')
+		return self._alice_txops('txcreate', menu='s', sweep_menu='3', sweep_type='sweep_all')
+
+	def alice_txcreate_sweep3(self):
+		return self._alice_txops('txcreate', menu='S', sweep_menu='12', sweep_type='sweep')
 
 	alice_txcreate3 = alice_txcreate2 = alice_txcreate1
 
@@ -807,7 +819,7 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 			add_opts    = self.alice_daemon_opts,
 			wait_signed = True)
 
-	alice_txsend1 = alice_txsend2 = alice_txsend3 = _alice_txsend
+	alice_txsend1 = alice_txsend2 = alice_txsend3 = alice_txsend4 = _alice_txsend
 
 	def alice_txstatus1(self):
 		return self._alice_txstatus(expect_str='TxID: .* in mempool')