From 4a4b81493526e23687d5b71a0df9095d2ba0e695 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 2 Feb 2026 09:56:58 +0000 Subject: [PATCH] XMR compat: export outputs files during TX creation Formerly, users were required to run `mmgen-xmrwallet export-outputs` at the beginning of each XMR autosigning session. This patch eliminates that requirement when transacting via the compatibility layer. --- mmgen/data/version | 2 +- mmgen/proto/xmr/tx/new.py | 10 ++++++++++ mmgen/xmrwallet/ops/sweep.py | 15 +++++++++++++++ test/cmdtest_d/autosign.py | 2 +- test/cmdtest_d/xmr_autosign.py | 20 ++++++++++++++++---- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index bfaf773c..0e6f7859 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -16.1.dev29 +16.1.dev30 diff --git a/mmgen/proto/xmr/tx/new.py b/mmgen/proto/xmr/tx/new.py index fd9c534a..11bf52ae 100755 --- a/mmgen/proto/xmr/tx/new.py +++ b/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() diff --git a/mmgen/xmrwallet/ops/sweep.py b/mmgen/xmrwallet/ops/sweep.py index 4b800708..cad459d8 100755 --- a/mmgen/xmrwallet/ops/sweep.py +++ b/mmgen/xmrwallet/ops/sweep.py @@ -168,6 +168,21 @@ class OpSweep(OpMixinSpec, OpWallet): 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( f'\n{self.stem.capitalize()}ing account #{self.account}' diff --git a/test/cmdtest_d/autosign.py b/test/cmdtest_d/autosign.py index 34ee93b5..1ca93bc8 100755 --- a/test/cmdtest_d/autosign.py +++ b/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) diff --git a/test/cmdtest_d/xmr_autosign.py b/test/cmdtest_d/xmr_autosign.py index 04877830..fcb12da5 100755 --- a/test/cmdtest_d/xmr_autosign.py +++ b/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', @@ -793,6 +802,9 @@ class CmdTestXMRCompat(CmdTestXMRAutosign): def alice_txcreate_sweep2(self): 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 def _alice_txabort(self): @@ -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')