Browse Source

mmgen-xmrwallet: new `export-outputs-sign` operation

The MMGen Project 1 year ago
parent
commit
c96908ee36
5 changed files with 47 additions and 26 deletions
  1. 7 3
      mmgen/autosign.py
  2. 9 5
      mmgen/help/xmrwallet.py
  3. 3 3
      mmgen/main_xmrwallet.py
  4. 18 9
      mmgen/xmrwallet.py
  5. 10 6
      test/cmdtest_py_d/ct_xmr_autosign.py

+ 7 - 3
mmgen/autosign.py

@@ -39,6 +39,7 @@ class Signable:
 
 		clean_all = False
 		multiple_ok = True
+		action_desc = 'signed'
 
 		def __init__(self,parent):
 			self.parent = parent
@@ -266,7 +267,6 @@ class Signable:
 		dir_name = 'xmr_outputs_dir'
 		clean_all = True
 		summary_footer = '\n'
-		action_desc = 'imported and signed'
 
 		async def sign(self,f):
 			from .xmrwallet import MoneroWalletOps,xmrwallet_uargs
@@ -278,8 +278,12 @@ class Signable:
 					wallets = str(wallet_idx),
 					spec    = None ),
 			)
-			obj = await m.main( f, wallet_idx, restart_daemon=self.need_daemon_restart(m,wallet_idx) )
-			obj.write()
+			obj = await m.main(f, wallet_idx, restart_daemon=self.need_daemon_restart(m,wallet_idx))
+			if obj.data.sign:
+				obj.write()
+				self.action_desc = 'imported and signed'
+			else:
+				self.action_desc = 'imported'
 			return obj
 
 	class message(base):

+ 9 - 5
mmgen/help/xmrwallet.py

@@ -63,6 +63,8 @@ restore   - same as ‘create’, but additionally restore wallet metadata from
             the corresponding JSON dump files created with ‘dump’
 export-outputs      - export outputs of watch-only wallets for import into
                       their corresponding offline wallets
+export-outputs-sign - same as above, plus request offline wallet to create
+                      signed key images for import by ‘import-key-images’
 import-key-images   - import key images signed by offline wallets into their
                       corresponding watch-only wallets
 
@@ -357,12 +359,14 @@ Then insert the removable device on the offline machine.  This will import
 the outputs into the corresponding signing wallet(s) (and optionally redo any
 failed transaction signing operation).
 
-Following a ‘resubmit’, add the --rescan-blockchain option:
+Following a ‘resubmit’, use the ‘export-outputs-sign’ operation instead, and
+add the --rescan-blockchain option:
 
-$ mmgen-xmrwallet --autosign --rescan-blockchain export-outputs <wallet index>
+$ mmgen-xmrwallet --autosign --rescan-blockchain export-outputs-sign <wallet index>
 
-Insert the removable device on your online machine and import the signed key
-images into your online wallet as follows:
+Here the offline signing wallet(s) will also create signed key images. Insert
+the removable device on your online machine and import the signed key images
+into your online wallet as follows:
 
 $ mmgen-xmrwallet --autosign import-key-images
 
@@ -421,7 +425,7 @@ in again and resume where you left off.
 
 Once your watch-only wallets are synced, you need to export their outputs:
 
-$ mmgen-xmrwallet --autosign export-outputs
+$ mmgen-xmrwallet --autosign export-outputs-sign
 
 Now insert the removable device on the offline machine and wait until the LED
 stops flashing (or ‘safe to extract’).  The wallet outputs are now imported

+ 3 - 3
mmgen/main_xmrwallet.py

@@ -48,7 +48,7 @@ opts_data = {
 			'[opts] relay    <TX_file>',
 			'[opts] resubmit | abort (for use with --autosign only)',
 			'[opts] txview | txlist [TX_file] ...',
-			'[opts] export-outputs | import-key-images [wallets]',
+			'[opts] export-outputs | export-outputs-sign | import-key-images [wallets]',
 		],
 		'options': """
 -h, --help                       Print this help message
@@ -107,7 +107,7 @@ cmd_args = cfg._args
 if cmd_args and cfg.autosign and (
 		cmd_args[0] in (
 			MoneroWalletOps.kafile_arg_ops
-			+ ('export-outputs','import-key-images','txview','txlist')
+			+ ('export-outputs', 'export-outputs-sign', 'import-key-images', 'txview', 'txlist')
 		)
 		or len(cmd_args) == 1 and cmd_args[0] in ('submit', 'resubmit', 'abort')
 	):
@@ -133,7 +133,7 @@ elif op in ('new','transfer','sweep','label'):
 	if len(cmd_args) != 1:
 		cfg._opts.usage()
 	spec = cmd_args[0]
-elif op in ('export-outputs','import-key-images'):
+elif op in ('export-outputs', 'export-outputs-sign', 'import-key-images'):
 	if not cfg.autosign: # --autosign only for now - TODO
 		die(f'--autosign must be used with command {op!r}')
 	if len(cmd_args) > 1:

+ 18 - 9
mmgen/xmrwallet.py

@@ -486,6 +486,7 @@ class MoneroWalletOutputsFile:
 			'wallet_index',
 			'outputs_data_hex',
 			'signed_key_images',
+			'sign',
 		])
 
 		def __init__(self,cfg):
@@ -527,7 +528,7 @@ class MoneroWalletOutputsFile:
 	class New(Base):
 		ext = 'raw'
 
-		def __init__( self, parent, wallet_fn, data, wallet_idx=None ):
+		def __init__(self, parent, wallet_fn, data, wallet_idx=None, sign=False):
 			super().__init__(parent.cfg)
 			self.wallet_fn = wallet_fn
 			init_data = dict.fromkeys(self.data_tuple._fields)
@@ -535,6 +536,8 @@ class MoneroWalletOutputsFile:
 				'seed_id':      parent.kal.al_id.sid,
 				'wallet_index': wallet_idx or parent.get_idx_from_fn(wallet_fn),
 			})
+			if sign:
+				init_data['sign'] = sign
 			init_data.update({k:v for k,v in data.items() if k in init_data})
 			self.data = self.data_tuple(**init_data)
 
@@ -1882,6 +1885,7 @@ class MoneroWalletOps:
 		action = 'exporting outputs from'
 		stem = 'process'
 		opts = ('rescan_blockchain',)
+		sign = False
 
 		async def process_wallet(self,d,fn,last):
 			h = self.rpc(self,d)
@@ -1904,10 +1908,14 @@ class MoneroWalletOps:
 				parent    = self,
 				wallet_fn = fn,
 				data      = self.c.call('export_outputs', all=True),
+				sign      = self.sign,
 			)
 			m.write()
 			return True
 
+	class export_outputs_sign(export_outputs):
+		sign = True
+
 	class import_outputs(wallet):
 		action = 'importing wallet outputs into'
 		start_daemon = False
@@ -1927,14 +1935,15 @@ class MoneroWalletOps:
 				outputs_data_hex = m.data.outputs_data_hex )
 			idata = res['num_imported']
 			bmsg(f'\n  {idata} output{suf(idata)} imported')
-			data = m.data._asdict()
-			data.update(self.c.call('export_key_images', all=True))
-			m = MoneroWalletOutputsFile.SignedNew(
-				parent    = self,
-				wallet_fn = m.get_wallet_fn(fn),
-				data      = data )
-			idata = m.data.signed_key_images or []
-			bmsg(f'  {len(idata)} key image{suf(idata)} signed')
+			if m.data.sign:
+				data = m.data._asdict()
+				data.update(self.c.call('export_key_images', all=True))
+				m = MoneroWalletOutputsFile.SignedNew(
+					parent    = self,
+					wallet_fn = m.get_wallet_fn(fn),
+					data      = data)
+				idata = m.data.signed_key_images or []
+				bmsg(f'  {len(idata)} key image{suf(idata)} signed')
 			return m
 
 	class import_key_images(wallet):

+ 10 - 6
test/cmdtest_py_d/ct_xmr_autosign.py

@@ -67,10 +67,11 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		('fund_alice1',              'sending funds to Alice (wallet #1)'),
 		('fund_alice2',              'sending funds to Alice (wallet #2)'),
 		('autosign_start_thread',    'starting autosign wait loop'),
+		('export_outputs1',          'exporting outputs from Alice’s watch-only wallet #1'),
 		('create_transfer_tx1',      'creating a transfer TX'),
 		('submit_transfer_tx1',      'submitting the transfer TX'),
 		('resubmit_transfer_tx1',    'resubmitting the transfer TX'),
-		('export_outputs1',          'exporting outputs from Alice’s watch-only wallet #1'),
+		('export_outputs2',          'exporting outputs from Alice’s watch-only wallet #1'),
 		('import_key_images1',       'importing signed key images into Alice’s online wallets'),
 		('sync_chkbal1',             'syncing Alice’s wallet #1'),
 		('abort_tx1',                'aborting the current transaction (error)'),
@@ -83,7 +84,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		('delete_wallets',           'deleting Alice’s wallets'),
 		('restore_wallets',          'creating online (watch-only) wallets for Alice'),
 		('delete_dump_files',        'deleting Alice’s dump files'),
-		('export_outputs2',          'exporting outputs from Alice’s watch-only wallets'),
+		('export_outputs3',          'exporting outputs from Alice’s watch-only wallets'),
 		('import_key_images2',       'importing signed key images into Alice’s online wallets'),
 		('sync_chkbal3',             'syncing Alice’s wallets and checking balance'),
 		('txlist',                   'listing Alice’s submitted transactions'),
@@ -353,10 +354,10 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		else:
 			return t
 
-	def _export_outputs(self,wallet_arg,add_opts=[]):
+	def _export_outputs(self, wallet_arg, op, add_opts=[]):
 		self.insert_device_online()
 		t = self._xmr_autosign_op(
-			op         = 'export-outputs',
+			op         = op,
 			wallet_arg = wallet_arg,
 			add_opts   = add_opts)
 		t.written_to_file('Wallet outputs')
@@ -364,10 +365,13 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		return t
 
 	def export_outputs1(self):
-		return self._export_outputs('1',['--rescan-blockchain'])
+		return self._export_outputs('1', op='export-outputs')
 
 	def export_outputs2(self):
-		return self._export_outputs('1-2')
+		return self._export_outputs('1', op='export-outputs-sign', add_opts=['--rescan-blockchain'])
+
+	def export_outputs3(self):
+		return self._export_outputs('1-2', op='export-outputs-sign')
 
 	def _import_key_images(self,wallet_arg):
 		self.insert_device_online()