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
 		clean_all = False
 		multiple_ok = True
 		multiple_ok = True
+		action_desc = 'signed'
 
 
 		def __init__(self,parent):
 		def __init__(self,parent):
 			self.parent = parent
 			self.parent = parent
@@ -266,7 +267,6 @@ class Signable:
 		dir_name = 'xmr_outputs_dir'
 		dir_name = 'xmr_outputs_dir'
 		clean_all = True
 		clean_all = True
 		summary_footer = '\n'
 		summary_footer = '\n'
-		action_desc = 'imported and signed'
 
 
 		async def sign(self,f):
 		async def sign(self,f):
 			from .xmrwallet import MoneroWalletOps,xmrwallet_uargs
 			from .xmrwallet import MoneroWalletOps,xmrwallet_uargs
@@ -278,8 +278,12 @@ class Signable:
 					wallets = str(wallet_idx),
 					wallets = str(wallet_idx),
 					spec    = None ),
 					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
 			return obj
 
 
 	class message(base):
 	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’
             the corresponding JSON dump files created with ‘dump’
 export-outputs      - export outputs of watch-only wallets for import into
 export-outputs      - export outputs of watch-only wallets for import into
                       their corresponding offline wallets
                       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
 import-key-images   - import key images signed by offline wallets into their
                       corresponding watch-only wallets
                       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
 the outputs into the corresponding signing wallet(s) (and optionally redo any
 failed transaction signing operation).
 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
 $ 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:
 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
 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
 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] relay    <TX_file>',
 			'[opts] resubmit | abort (for use with --autosign only)',
 			'[opts] resubmit | abort (for use with --autosign only)',
 			'[opts] txview | txlist [TX_file] ...',
 			'[opts] txview | txlist [TX_file] ...',
-			'[opts] export-outputs | import-key-images [wallets]',
+			'[opts] export-outputs | export-outputs-sign | import-key-images [wallets]',
 		],
 		],
 		'options': """
 		'options': """
 -h, --help                       Print this help message
 -h, --help                       Print this help message
@@ -107,7 +107,7 @@ cmd_args = cfg._args
 if cmd_args and cfg.autosign and (
 if cmd_args and cfg.autosign and (
 		cmd_args[0] in (
 		cmd_args[0] in (
 			MoneroWalletOps.kafile_arg_ops
 			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')
 		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:
 	if len(cmd_args) != 1:
 		cfg._opts.usage()
 		cfg._opts.usage()
 	spec = cmd_args[0]
 	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
 	if not cfg.autosign: # --autosign only for now - TODO
 		die(f'--autosign must be used with command {op!r}')
 		die(f'--autosign must be used with command {op!r}')
 	if len(cmd_args) > 1:
 	if len(cmd_args) > 1:

+ 18 - 9
mmgen/xmrwallet.py

@@ -486,6 +486,7 @@ class MoneroWalletOutputsFile:
 			'wallet_index',
 			'wallet_index',
 			'outputs_data_hex',
 			'outputs_data_hex',
 			'signed_key_images',
 			'signed_key_images',
+			'sign',
 		])
 		])
 
 
 		def __init__(self,cfg):
 		def __init__(self,cfg):
@@ -527,7 +528,7 @@ class MoneroWalletOutputsFile:
 	class New(Base):
 	class New(Base):
 		ext = 'raw'
 		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)
 			super().__init__(parent.cfg)
 			self.wallet_fn = wallet_fn
 			self.wallet_fn = wallet_fn
 			init_data = dict.fromkeys(self.data_tuple._fields)
 			init_data = dict.fromkeys(self.data_tuple._fields)
@@ -535,6 +536,8 @@ class MoneroWalletOutputsFile:
 				'seed_id':      parent.kal.al_id.sid,
 				'seed_id':      parent.kal.al_id.sid,
 				'wallet_index': wallet_idx or parent.get_idx_from_fn(wallet_fn),
 				'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})
 			init_data.update({k:v for k,v in data.items() if k in init_data})
 			self.data = self.data_tuple(**init_data)
 			self.data = self.data_tuple(**init_data)
 
 
@@ -1882,6 +1885,7 @@ class MoneroWalletOps:
 		action = 'exporting outputs from'
 		action = 'exporting outputs from'
 		stem = 'process'
 		stem = 'process'
 		opts = ('rescan_blockchain',)
 		opts = ('rescan_blockchain',)
+		sign = False
 
 
 		async def process_wallet(self,d,fn,last):
 		async def process_wallet(self,d,fn,last):
 			h = self.rpc(self,d)
 			h = self.rpc(self,d)
@@ -1904,10 +1908,14 @@ class MoneroWalletOps:
 				parent    = self,
 				parent    = self,
 				wallet_fn = fn,
 				wallet_fn = fn,
 				data      = self.c.call('export_outputs', all=True),
 				data      = self.c.call('export_outputs', all=True),
+				sign      = self.sign,
 			)
 			)
 			m.write()
 			m.write()
 			return True
 			return True
 
 
+	class export_outputs_sign(export_outputs):
+		sign = True
+
 	class import_outputs(wallet):
 	class import_outputs(wallet):
 		action = 'importing wallet outputs into'
 		action = 'importing wallet outputs into'
 		start_daemon = False
 		start_daemon = False
@@ -1927,14 +1935,15 @@ class MoneroWalletOps:
 				outputs_data_hex = m.data.outputs_data_hex )
 				outputs_data_hex = m.data.outputs_data_hex )
 			idata = res['num_imported']
 			idata = res['num_imported']
 			bmsg(f'\n  {idata} output{suf(idata)} 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
 			return m
 
 
 	class import_key_images(wallet):
 	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_alice1',              'sending funds to Alice (wallet #1)'),
 		('fund_alice2',              'sending funds to Alice (wallet #2)'),
 		('fund_alice2',              'sending funds to Alice (wallet #2)'),
 		('autosign_start_thread',    'starting autosign wait loop'),
 		('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'),
 		('create_transfer_tx1',      'creating a transfer TX'),
 		('submit_transfer_tx1',      'submitting the transfer TX'),
 		('submit_transfer_tx1',      'submitting the transfer TX'),
 		('resubmit_transfer_tx1',    'resubmitting 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'),
 		('import_key_images1',       'importing signed key images into Alice’s online wallets'),
 		('sync_chkbal1',             'syncing Alice’s wallet #1'),
 		('sync_chkbal1',             'syncing Alice’s wallet #1'),
 		('abort_tx1',                'aborting the current transaction (error)'),
 		('abort_tx1',                'aborting the current transaction (error)'),
@@ -83,7 +84,7 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		('delete_wallets',           'deleting Alice’s wallets'),
 		('delete_wallets',           'deleting Alice’s wallets'),
 		('restore_wallets',          'creating online (watch-only) wallets for Alice'),
 		('restore_wallets',          'creating online (watch-only) wallets for Alice'),
 		('delete_dump_files',        'deleting Alice’s dump files'),
 		('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'),
 		('import_key_images2',       'importing signed key images into Alice’s online wallets'),
 		('sync_chkbal3',             'syncing Alice’s wallets and checking balance'),
 		('sync_chkbal3',             'syncing Alice’s wallets and checking balance'),
 		('txlist',                   'listing Alice’s submitted transactions'),
 		('txlist',                   'listing Alice’s submitted transactions'),
@@ -353,10 +354,10 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		else:
 		else:
 			return t
 			return t
 
 
-	def _export_outputs(self,wallet_arg,add_opts=[]):
+	def _export_outputs(self, wallet_arg, op, add_opts=[]):
 		self.insert_device_online()
 		self.insert_device_online()
 		t = self._xmr_autosign_op(
 		t = self._xmr_autosign_op(
-			op         = 'export-outputs',
+			op         = op,
 			wallet_arg = wallet_arg,
 			wallet_arg = wallet_arg,
 			add_opts   = add_opts)
 			add_opts   = add_opts)
 		t.written_to_file('Wallet outputs')
 		t.written_to_file('Wallet outputs')
@@ -364,10 +365,13 @@ class CmdTestXMRAutosign(CmdTestXMRWallet,CmdTestAutosignThreaded):
 		return t
 		return t
 
 
 	def export_outputs1(self):
 	def export_outputs1(self):
-		return self._export_outputs('1',['--rescan-blockchain'])
+		return self._export_outputs('1', op='export-outputs')
 
 
 	def export_outputs2(self):
 	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):
 	def _import_key_images(self,wallet_arg):
 		self.insert_device_online()
 		self.insert_device_online()