Browse Source

XMR compat: addrimport support

Example (assumes --autosign):

    $ mmgen-addrimport --coin=xmr

Testing/demo:

    $ test/cmdtest.py --coin=xmr -e -X addrimport_alice2 xmr_compat

More info:

    $ mmgen-addrimport --help
The MMGen Project 3 weeks ago
parent
commit
d8439ba691
4 changed files with 73 additions and 10 deletions
  1. 1 1
      mmgen/data/version
  2. 43 0
      mmgen/main_addrimport.py
  3. 18 3
      test/cmdtest_d/xmr_autosign.py
  4. 11 6
      test/cmdtest_d/xmrwallet.py

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-16.1.dev30
+16.1.dev31

+ 43 - 0
mmgen/main_addrimport.py

@@ -33,6 +33,10 @@ opts_data = {
 		'options': """
 		'options': """
 -h, --help         Print this help message
 -h, --help         Print this help message
 --, --longhelp     Print help message for long (global) options
 --, --longhelp     Print help message for long (global) options
+-a, --autosign     Import addresses from pre-created key-address file on the
+                   removable device.  The removable device is mounted and
+                   unmounted automatically.  This option is available for XMR
+                   only (see XMR NOTES below).
 -A, --address=ADDR Import the single coin address ADDR
 -A, --address=ADDR Import the single coin address ADDR
 -b, --batch        Import all addresses in one RPC call
 -b, --batch        Import all addresses in one RPC call
 -l, --addrlist     Address source is a flat list of non-MMGen coin addresses
 -l, --addrlist     Address source is a flat list of non-MMGen coin addresses
@@ -45,6 +49,25 @@ opts_data = {
 -t, --token-addr=ADDR Import addresses for ERC20 token with address ADDR
 -t, --token-addr=ADDR Import addresses for ERC20 token with address ADDR
 """,
 """,
 	'notes': """
 	'notes': """
+                                   XMR NOTES
+
+For Monero, --autosign is required, and a key-address file on the removable
+device is used instead of an address file.  Specifying the file explicitly
+on the command line is not supported.
+
+When ‘mmgen-autosign setup’ (or ‘xmr_setup’) is run with the --xmrwallets
+option, an ephemeral Monero wallet is created for each wallet number listed,
+to be used for transaction signing. In addition, a key-address file is created
+on the removable device, with an address and viewkey matching the base address
+of each signing wallet.
+
+This script uses that file to create an online view-only tracking wallet to
+match each offline signing wallet.  If a tracking wallet for a given address
+already exists, it is left untouched and no action is performed.  To create
+additional tracking wallets, just specify new wallet numbers via --xmrwallets
+during the offline setup process.
+
+
                            NOTES FOR BTC, LTC AND BCH
                            NOTES FOR BTC, LTC AND BCH
 
 
 Rescanning now uses the ‘scantxoutset’ RPC call and a selective scan of
 Rescanning now uses the ‘scantxoutset’ RPC call and a selective scan of
@@ -133,8 +156,28 @@ def check_opts(twctl):
 
 
 	return batch, rescan
 	return batch, rescan
 
 
+def check_xmr_args():
+	for k in ('address', 'batch', 'addrlist', 'keyaddr_file', 'rescan', 'token_addr'):
+		if getattr(cfg, k):
+			die(1, 'Option --{} not supported for XMR'.format(k.replace('_', '-')))
+	if not cfg.autosign:
+		die(1, 'For XMR address import, --autosign is required')
+	if cfg._args:
+		die(1, 'Address file arg not supported with --autosign')
+
 async def main():
 async def main():
 
 
+	if cfg._proto.base_coin == 'XMR':
+		from .tx.util import mount_removable_device
+		from .xmrwallet import op as xmrwallet_op
+		check_xmr_args()
+		mount_removable_device(cfg)
+		op = xmrwallet_op('create', cfg, None, None, compat_call=True)
+		if op.to_process:
+			await op.restart_wallet_daemon()
+			await op.main()
+		return
+
 	from .tw.ctl import TwCtl
 	from .tw.ctl import TwCtl
 	twctl = await TwCtl(
 	twctl = await TwCtl(
 		cfg        = cfg,
 		cfg        = cfg,

+ 18 - 3
test/cmdtest_d/xmr_autosign.py

@@ -520,7 +520,8 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 	cmd_group = (
 	cmd_group = (
 		('autosign_setup',           'autosign setup with Alice’s seed'),
 		('autosign_setup',           'autosign setup with Alice’s seed'),
 		('autosign_xmr_setup',       'autosign setup (creation of Monero signing wallets)'),
 		('autosign_xmr_setup',       'autosign setup (creation of Monero signing wallets)'),
-		('create_watchonly_wallets', 'creating Alice’s watch-only wallets'),
+		('addrimport_alice',         'creating (importing) Alice’s watch-only wallets from key-address file'),
+		('addrimport_alice2',        'reimporting Alice’s watch-only wallets from key-address file'),
 		('gen_kafile_miner',         'generating key-address file for Miner'),
 		('gen_kafile_miner',         'generating key-address file for Miner'),
 		('create_wallet_miner',      'creating Monero wallet for Miner'),
 		('create_wallet_miner',      'creating Monero wallet for Miner'),
 		('mine_initial_coins',       'mining initial coins'),
 		('mine_initial_coins',       'mining initial coins'),
@@ -601,8 +602,22 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
 			'--monero-wallet-rpc-password=passwOrd']
 			'--monero-wallet-rpc-password=passwOrd']
 		self.alice_opts = ['--alice', '--coin=xmr'] + self.alice_daemon_opts
 		self.alice_opts = ['--alice', '--coin=xmr'] + self.alice_daemon_opts
 
 
-	def create_watchonly_wallets(self):
-		return self._create_wallets()
+	def addrimport_alice(self):
+		return self._addrimport_alice(create_address_files=True)
+
+	def addrimport_alice2(self):
+		return self._addrimport_alice(expect_str='Skipping.*Skipping')
+
+	def _addrimport_alice(self, *, expect_str=None, create_address_files=False):
+		self.insert_device_online()
+		t = self.spawn('mmgen-addrimport', self.alice_opts + self.autosign_opts)
+		if expect_str:
+			t.expect(expect_str, regex=True)
+		if create_address_files:
+			self._create_address_files(t, 'alice')
+		t.read() # required!
+		self.remove_device_online()
+		return t
 
 
 	async def mine_blocks_1(self):
 	async def mine_blocks_1(self):
 		return await self._mine_blocks(1)
 		return await self._mine_blocks(1)

+ 11 - 6
test/cmdtest_d/xmrwallet.py

@@ -293,6 +293,16 @@ class CmdTestXMRWallet(CmdTestBase):
 	def create_wallets_alice(self):
 	def create_wallets_alice(self):
 		return self.create_wallets('alice')
 		return self.create_wallets('alice')
 
 
+	def _create_address_files(self, t, user, wallet=None):
+		data = self.users[user]
+		for i in MMGenRange(wallet or data.kal_range).items:
+			write_data_to_file(
+				self.cfg,
+				data.addrfile_fs.format(i),
+				t.expect_getend('Address: '),
+				ask_overwrite = False,
+				quiet = True)
+
 	def create_wallets(self, user, wallet=None, add_opts=[], op='create'):
 	def create_wallets(self, user, wallet=None, add_opts=[], op='create'):
 		assert wallet is None or is_int(wallet), 'wallet arg'
 		assert wallet is None or is_int(wallet), 'wallet arg'
 		data = self.users[user]
 		data = self.users[user]
@@ -311,12 +321,7 @@ class CmdTestXMRWallet(CmdTestBase):
 			+ [op]
 			+ [op]
 			+ ([] if data.autosign else [data.kafile])
 			+ ([] if data.autosign else [data.kafile])
 			+ [wallet or data.kal_range])
 			+ [wallet or data.kal_range])
-		for i in MMGenRange(wallet or data.kal_range).items:
-			write_data_to_file(
-				self.cfg,
-				self.users[user].addrfile_fs.format(i),
-				t.expect_getend('Address: '),
-				quiet = True)
+		self._create_address_files(t, user, wallet)
 		return t
 		return t
 
 
 	def new_addr_alice(self, spec, cfg, expect, kafile=None, do_autosign=False):
 	def new_addr_alice(self, spec, cfg, expect, kafile=None, do_autosign=False):