Browse Source

autosign,xmrwallet: various fixes and cleanups

The MMGen Project 1 year ago
parent
commit
c4f0954614

+ 1 - 2
mmgen/autosign.py

@@ -131,7 +131,6 @@ class Signable:
 			gmsg('\nSigned message files:')
 			for m in messages:
 				gmsg('  ' + os.path.join( self.dir, m.signed_filename ))
-			return
 
 		def gen_bad_list(self,bad_files):
 			for f in bad_files:
@@ -185,7 +184,7 @@ class Autosign:
 		cfg.outdir = self.tx_dir
 		cfg.passwd_file = self.keyfile
 
-		if 'coin' in cfg._uopts:
+		if 'coin' in cfg._uopts and not any(k in cfg._uopts for k in ('help','longhelp')):
 			die(1,'--coin option not supported with this command.  Use --coins instead')
 
 		self.coins = cfg.coins.upper().split(',') if cfg.coins else []

+ 1 - 3
mmgen/main_xmrwallet.py

@@ -37,9 +37,7 @@ opts_data = {
 		'desc': """Perform various Monero wallet operations for addresses
                    in an MMGen XMR key-address file""",
 		'usage2': [
-			'[opts] create   <xmr_keyaddrfile> [wallets]',
-			'[opts] sync     <xmr_keyaddrfile> [wallets]',
-			'[opts] list     <xmr_keyaddrfile> [wallets]',
+			'[opts] create | sync | list <xmr_keyaddrfile> [wallets]',
 			'[opts] label    <xmr_keyaddrfile> LABEL_SPEC',
 			'[opts] new      <xmr_keyaddrfile> NEW_ADDRESS_SPEC',
 			'[opts] transfer <xmr_keyaddrfile> TRANSFER_SPEC',

+ 1 - 1
mmgen/wallet/enc.py

@@ -13,7 +13,7 @@ wallet.enc: encrypted wallet base class
 """
 
 from ..cfg import gc
-from ..util import msg,make_chksum_8
+from ..util import msg,make_chksum_8,die
 from .base import wallet
 
 class wallet(wallet):

+ 52 - 41
mmgen/xmrwallet.py

@@ -40,6 +40,7 @@ from .util import (
 	make_chksum_6,
 	capfirst,
 )
+from .fileutil import get_data_from_file
 from .seed import SeedID
 from .protocol import init_proto
 from .proto.btc.common import b58a
@@ -111,12 +112,7 @@ def is_xmr_tx_file(cfg,fn):
 			ymsg(f'\n{type(e).__name__}: {e}')
 		return False
 
-class MoneroMMGenTX:
-
-	class Base:
-
-		def __init__(self):
-			self.name = type(self).__name__
+class MoneroMMGenFile:
 
 		def make_chksum(self,keys=None):
 			res = json.dumps(
@@ -127,14 +123,39 @@ class MoneroMMGenTX:
 
 		@property
 		def base_chksum(self):
-			return self.make_chksum(
-				('op','create_time','network','seed_id','source','dest','amount')
-			)
+			return self.make_chksum(self.base_chksum_fields)
 
 		@property
 		def full_chksum(self):
-			return self.make_chksum(set(self.data._fields) - {'metadata'})
+			return self.make_chksum(self.full_chksum_fields)
 
+		def check_checksums(self,d_wrap):
+			for k in ('base_chksum','full_chksum'):
+				a = getattr(self,k)
+				b = d_wrap[k]
+				assert a == b, f'{k} mismatch: {a} != {b}'
+
+		def make_wrapped_data(self,in_data):
+			return json.dumps(
+				{ self.data_label: {
+						'base_chksum': self.base_chksum,
+						'full_chksum': self.full_chksum,
+						'data': in_data,
+					}
+				},
+				cls = json_encoder,
+			)
+
+		def extract_data_from_file(self,cfg,fn):
+			return json.loads( get_data_from_file( cfg, fn, self.desc ))[self.data_label]
+
+class MoneroMMGenTX:
+
+	class Base(MoneroMMGenFile):
+
+		data_label = 'MoneroMMGenTX'
+		base_chksum_fields = ('op','create_time','network','seed_id','source','dest','amount')
+		full_chksum_fields = ('op','create_time','network','seed_id','source','dest','amount','fee','blob')
 		xmrwallet_tx_data = namedtuple('xmrwallet_tx_data',[
 			'op',
 			'create_time',
@@ -151,10 +172,13 @@ class MoneroMMGenTX:
 			'metadata',
 		])
 
+		def __init__(self):
+			self.name = type(self).__name__
+
 		def get_info(self,indent=''):
 			d = self.data
 			if d.dest:
-				to_entry = f'\n{indent}  To:     ' + (
+				to_entry = f'\n{indent}  To:      ' + (
 					'Wallet {}, account {}, address {}'.format(
 						d.dest.wallet.hl(),
 						red(f'#{d.dest.account}'),
@@ -203,16 +227,6 @@ class MoneroMMGenTX:
 			if delete_metadata:
 				dict_data['metadata'] = None
 
-			out = json.dumps(
-				{ 'MoneroMMGenTX': {
-						'base_chksum': self.base_chksum,
-						'full_chksum': self.full_chksum,
-						'data': dict_data,
-					}
-				},
-				cls = json_encoder,
-			)
-
 			fn = '{a}{b}-XMR[{c!s}]{d}.{e}'.format(
 				a = self.base_chksum.upper(),
 				b = (lambda s: f'-{s.upper()}' if s else '')(self.full_chksum),
@@ -225,7 +239,7 @@ class MoneroMMGenTX:
 			write_data_to_file(
 				cfg                   = self.cfg,
 				outfile               = fn,
-				data                  = out,
+				data                  = self.make_wrapped_data(dict_data),
 				desc                  = self.desc,
 				ask_write             = ask_write,
 				ask_write_default_yes = not ask_write,
@@ -276,10 +290,8 @@ class MoneroMMGenTX:
 			self.cfg = cfg
 			self.fn = fn
 
-			from .fileutil import get_data_from_file
-
 			try:
-				d_wrap = json.loads(get_data_from_file( cfg, fn ))['MoneroMMGenTX']
+				d_wrap = self.extract_data_from_file( cfg, fn )
 			except Exception as e:
 				die( 'MoneroMMGenTXFileParseError', f'{type(e).__name__}: {e}\nCould not load transaction file' )
 
@@ -307,10 +319,7 @@ class MoneroMMGenTX:
 				metadata       = d.metadata,
 			)
 
-			for k in ('base_chksum','full_chksum'):
-				a = getattr(self,k)
-				b = d_wrap[k]
-				assert a == b, f'{k} mismatch: {a} != {b}'
+			self.check_checksums(d_wrap)
 
 	class Signed(Completed):
 		desc = 'signed transaction'
@@ -404,11 +413,14 @@ class MoneroWalletOps:
 				if getattr(self.cfg,opt,None):
 					check_pat_opt(opt)
 
-		def display_tx_relay_info(self,indent=''):
-			m = re.fullmatch(
+		def parse_tx_relay_opt(self):
+			return re.fullmatch(
 				uarg_info['tx_relay_daemon'].pat,
 				self.cfg.tx_relay_daemon,
 				re.ASCII )
+
+		def display_tx_relay_info(self,indent=''):
+			m = self.parse_tx_relay_opt()
 			msg(fmt(f"""
 				TX relay info:
 				  Host:  {blue(m[1])}
@@ -431,6 +443,7 @@ class MoneroWalletOps:
 			'no_stop_wallet_daemon',
 		)
 		wallet_exists = True
+		skip_wallet_check = False # for debugging
 
 		def __init__(self,cfg,uarg_tuple):
 
@@ -456,9 +469,12 @@ class MoneroWalletOps:
 				addrfile = uarg.infile,
 				key_address_validity_check = True )
 
+			msg('')
+
 			self.create_addr_data()
 
-			check_wallets()
+			if not self.skip_wallet_check:
+				check_wallets()
 
 			self.wd = MoneroWalletDaemon(
 				cfg         = self.cfg,
@@ -468,8 +484,9 @@ class MoneroWalletOps:
 				daemon_addr = self.cfg.daemon or None,
 			)
 
+			u = self.wd.usr_daemon_args = []
 			if self.name == 'create' and self.cfg.restore_height is None:
-				self.wd.usr_daemon_args = ['--offline']
+				u.append('--offline')
 
 			self.c = MoneroWalletRPCClient(
 				cfg             = self.cfg,
@@ -927,10 +944,7 @@ class MoneroWalletOps:
 
 		def init_tx_relay_daemon(self):
 
-			m = re.fullmatch(
-				uarg_info['tx_relay_daemon'].pat,
-				self.cfg.tx_relay_daemon,
-				re.ASCII )
+			m = self.parse_tx_relay_opt()
 
 			wd2 = MoneroWalletDaemon(
 				cfg         = self.cfg,
@@ -1131,10 +1145,7 @@ class MoneroWalletOps:
 			self.tx = MoneroMMGenTX.Signed( self.cfg, uarg.infile )
 
 			if self.cfg.tx_relay_daemon:
-				m = re.fullmatch(
-					uarg_info['tx_relay_daemon'].pat,
-					self.cfg.tx_relay_daemon,
-					re.ASCII )
+				m = self.parse_tx_relay_opt()
 				host,port = m[1].split(':')
 				proxy = m[2]
 				md = None

+ 12 - 5
test/test_py_d/common.py

@@ -106,10 +106,17 @@ def restore_debug():
 	for k in save_debug:
 		os.environ[k] = save_debug[k] or ''
 
-def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete_all=False):
+def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete_all=False,substr=False):
 
-	dot = ('.','')[bool(no_dot)]
-	flist = [os.path.join(tdir,f) for f in os.listdir(tdir) if f == ext or f[-len(dot+ext):] == dot+ext]
+	dot = '' if no_dot else '.'
+
+	def have_match(fn):
+		return (
+			fn == ext
+			or fn.endswith( dot + ext )
+			or (substr and ext in fn) )
+
+	flist = [f.path for f in os.scandir(tdir) if have_match(f.name)]
 
 	if not flist:
 		return False
@@ -121,9 +128,9 @@ def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete
 		if delete or delete_all:
 			if (cfg.exact_output or cfg.verbose) and not cfg.quiet:
 				if delete_all:
-					msg(f'Deleting all *.{ext} files in {tdir!r}')
+					msg(f'Deleting all *{dot}{ext} files in {tdir!r}')
 				else:
-					msg(f'Multiple *.{ext} files in {tdir!r} - deleting')
+					msg(f'Multiple *{dot}{ext} files in {tdir!r} - deleting')
 			for f in flist:
 				os.unlink(f)
 		return False

+ 3 - 3
test/test_py_d/ts_autosign.py

@@ -296,14 +296,14 @@ class TestSuiteAutosignBase(TestSuiteBase):
 					os.unlink(os.path.join( destdir, os.path.basename(fn).replace('rawmsg','sigmsg') ))
 		return 'ok'
 
-	def do_sign(self,args,have_msg=False):
+	def do_sign(self,args,have_msg=False,tx_name='transaction'):
 		t = self.spawn('mmgen-autosign', self.opts + args )
 		t.expect(
-			f'{self.tx_count} transaction{suf(self.tx_count)} signed' if self.tx_count else
+			f'{self.tx_count} {tx_name}{suf(self.tx_count)} signed' if self.tx_count else
 			'No unsigned transactions' )
 
 		if self.bad_tx_count:
-			t.expect(f'{self.bad_tx_count} transaction{suf(self.bad_tx_count)} failed to sign')
+			t.expect(f'{self.bad_tx_count} {tx_name}{suf(self.bad_tx_count)} failed to sign')
 			t.req_exit_val = 1
 
 		if have_msg:

+ 3 - 3
test/test_py_d/ts_misc.py

@@ -51,10 +51,10 @@ class TestSuiteMisc(TestSuiteBase):
 		t = self.spawn(f'mmgen-xmrwallet',['txview','test/ref/monero/3EBD06-2D6E3B-XMR[0.74].testnet.sigtx'])
 		res = strip_ansi_escapes(t.read()).replace('\r','')
 		for s in (
-			'Amount: 0.74 XMR',
-			'Dest:   56VQ9M6k',
+			'Amount:  0.74 XMR',
+			'Dest:    56VQ9M6k',
 		):
-			assert s in res, s
+			assert s in res, f'{s} not in {res}'
 		return t
 
 	def coin_daemon_info(self):

+ 10 - 8
test/test_py_d/ts_xmrwallet.py

@@ -315,16 +315,18 @@ class TestSuiteXMRWallet(TestSuiteBase):
 	def create_wallets(self,user,wallet=None,add_opts=[]):
 		assert wallet is None or is_int(wallet), 'wallet arg'
 		data = self.users[user]
-		run(
-			'rm -f {}*'.format( data.walletfile_fs.format(wallet or '*') ),
-			shell = True
-		)
-		dir_opt = [f'--wallet-dir={data.udir}']
+		stem_glob = data.walletfile_fs.format(wallet or '*')
+		for glob in (
+				stem_glob,
+				stem_glob + '.keys',
+				stem_glob + '.address.txt' ):
+#			imsg(f'rm -f {glob}')
+			run( f'rm -f {glob}', shell=True )
 		t = self.spawn(
 			'mmgen-xmrwallet',
-			self.extra_opts
+			[f'--wallet-dir={data.udir}']
+			+ self.extra_opts
 			+ add_opts
-			+ dir_opt
 			+ ['create']
 			+ [data.kafile]
 			+ [wallet or data.kal_range]
@@ -350,7 +352,7 @@ class TestSuiteXMRWallet(TestSuiteBase):
 			[ 'new', data.kafile, spec ] )
 		res = strip_ansi_escapes(t.read()).replace('\r','')
 		m = re.search(expect,res,re.DOTALL)
-		assert m, m
+		assert m, f'no match found for {expect!r}'
 		return t
 
 	na_idx = 1