Browse Source

minor fixes and cleanups

The MMGen Project 2 years ago
parent
commit
3823e8cdc9

+ 1 - 1
mmgen/addrdata.py

@@ -94,7 +94,7 @@ class TwAddrData(AddrData,metaclass=AsyncInit):
 				out[al_id].append(AddrListEntry(self.proto,idx=obj.idx,addr=addr_array[0],label=l.comment))
 				i += 1
 
-		vmsg(f'{i} {g.prog_name} addresses found, {len(twd)} accounts total')
+		vmsg(f'{i} {g.proj_name} addresses found, {len(twd)} accounts total')
 
 		for al_id in out:
 			self.add(AddrList(self.proto,al_id=al_id,adata=AddrListData(sorted(out[al_id],key=lambda a: a.idx))))

+ 4 - 6
mmgen/base_proto/bitcoin/regtest.py

@@ -56,12 +56,10 @@ def create_hdseed(proto):
 def cliargs_convert(args):
 	def gen():
 		for arg in args:
-			if arg.lower() in ('true','false'):
-				yield (True,False)[arg.lower() == 'false']
-			elif len(str(arg)) < 20 and re.match(r'[0-9]+',arg):
-				yield int(arg)
-			else:
-				yield arg
+			try:
+				yield json.loads(arg) # list, dict, bool, int, null
+			except:
+				yield arg # arbitrary string
 
 	return tuple(gen())
 

+ 1 - 1
mmgen/base_proto/bitcoin/rpc.py

@@ -258,7 +258,7 @@ class BitcoinRPCClient(RPCClient,metaclass=AsyncInit):
 		'getmempoolentry',
 		'getrawtransaction',
 		'gettransaction',
-		'importaddress',
+		'importaddress', # address (address or script) label rescan p2sh (Add P2SH version of the script)
 		'listaccounts',
 		'listlabels',
 		'listunspent',

+ 1 - 2
mmgen/base_proto/bitcoin/tw/txhistory.py

@@ -258,8 +258,7 @@ Actions: [q]uit, r[e]draw:
 		#                         chain. e.g. 1 would mean the best block hash. Note: this is not used
 		#                         as a filter, but only affects [lastblock] in the return value
 		# 3. include_watchonly    (boolean, optional, default=true for watch-only wallets, otherwise
-		#                         false) Include transactions to watch-only addresses (see
-		#                         'importaddress')
+		#                         false) Include transactions to watch-only addresses
 		# 4. include_removed      (boolean, optional, default=true) Show transactions that were removed
 		#                         due to a reorg in the "removed" array (not guaranteed to work on
 		#                         pruned nodes)

+ 28 - 29
mmgen/main_addrimport.py

@@ -26,31 +26,10 @@ from .common import *
 from .addrlist import AddrList,KeyAddrList
 from .tw.common import TwLabel
 
-ai_msgs = lambda k: {
-	'rescan': """
-WARNING: You've chosen the '--rescan' option.  Rescanning the blockchain is
-necessary only if an address you're importing is already in the blockchain,
-has a balance and is not in your tracking wallet.  Note that the rescanning
-process is very slow (>30 min. for each imported address on a low-powered
-computer).
-	""".strip() if opt.rescan else """
-WARNING: If any of the addresses you're importing is already in the blockchain,
-has a balance and is not in your tracking wallet, you must exit the program now
-and rerun it using the '--rescan' option.
-""".strip(),
-	'bad_args': f"""
-You must specify an {g.proj_name} address file, a single address with the '--address'
-option, or a list of non-{g.proj_name} addresses with the '--addrlist' option
-""".strip()
-}[k]
-
-# In batch mode, daemon just rescans each address separately anyway, so make
-# --batch and --rescan incompatible.
-
 opts_data = {
 	'text': {
 		'desc': f'Import addresses into an {g.proj_name} tracking wallet',
-		'usage':'[opts] [mmgen address file]',
+		'usage':'[opts] [MMGen address file]',
 		'options': """
 -h, --help         Print this help message
 --, --longhelp     Print help message for long options (common options)
@@ -72,6 +51,23 @@ The --batch and --rescan options cannot be used together.
 	}
 }
 
+addrimport_msgs = {
+	'rescan': """
+		WARNING: You’ve chosen the ‘--rescan’ option.  Rescanning the blockchain is
+		necessary only if an address you’re importing is already in an output or
+		outputs in the blockchain but not all transactions involving the address
+		are known to the tracking wallet.
+
+		Rescanning is performed via the UTXO method, which is only minimally affected
+		by the number of addresses imported and typically takes just a few minutes.
+	""",
+	'bad_args': f"""
+		You must specify either an {g.proj_name} address file, a single address with
+		the ‘--address’ option, or a flat list of non-{g.proj_name} addresses with
+		the ‘--addrlist’ option.
+	"""
+}
+
 def parse_cmd_args(rpc,cmd_args):
 
 	def import_mmgen_list(infile):
@@ -96,7 +92,7 @@ def parse_cmd_args(rpc,cmd_args):
 		al = AddrList(proto=proto,addrlist=[opt.address])
 		infile = 'command line'
 	else:
-		die(1,ai_msgs('bad_args'))
+		die(1,addrimport_msgs['bad_args'])
 
 	return al,infile
 
@@ -105,17 +101,17 @@ def check_opts(tw):
 	rescan = bool(opt.rescan)
 
 	if rescan and not 'rescan' in tw.caps:
-		msg(f"'--rescan' ignored: not supported by {type(tw).__name__}")
+		msg(f"‘--rescan’ ignored: not supported by {type(tw).__name__}")
 		rescan = False
 
 	if rescan and not opt.quiet:
-		confirm_or_raise(
-			message = ai_msgs('rescan'),
-			action  = 'continue',
-			expect  = 'YES' )
+		if not keypress_confirm(
+				'\n{}\n\nContinue?'.format(addrimport_msgs['rescan']),
+				default_yes = True ):
+			die(1,'Exiting at user request')
 
 	if batch and not 'batch' in tw.caps:
-		msg(f"'--batch' ignored: not supported by {type(tw).__name__}")
+		msg(f"‘--batch’ ignored: not supported by {type(tw).__name__}")
 		batch = False
 
 	return batch,rescan
@@ -176,6 +172,9 @@ async def main():
 	from .rpc import rpc_init
 	tw.rpc = await rpc_init(proto)
 
+	for k,v in addrimport_msgs.items():
+		addrimport_msgs[k] = fmt(v,indent='  ',strip_char='\t').rstrip()
+
 	al,infile = parse_cmd_args(tw.rpc,cmd_args)
 
 	qmsg(

+ 1 - 0
mmgen/rpc.py

@@ -106,6 +106,7 @@ class RPCBackends:
 			self.timeout        = caller.timeout
 			self.http_hdrs      = caller.http_hdrs
 			self.make_host_path = caller.make_host_path
+			self.name           = type(self).__name__
 
 	class aiohttp(base):
 		"""

+ 2 - 1
mmgen/tool/rpc.py

@@ -161,7 +161,8 @@ class tool_cmd(tool_cmd_base):
 	async def remove_address(self,mmgen_or_coin_addr:str):
 		"remove an address from tracking wallet"
 		from ..tw.ctl import TrackingWallet
-		ret = await (await TrackingWallet(self.proto,mode='w')).remove_address(mmgen_or_coin_addr) # returns None on failure
+		# returns None on failure:
+		ret = await (await TrackingWallet(self.proto,mode='w')).remove_address(mmgen_or_coin_addr)
 		if ret:
 			from ..util import msg
 			msg(f'Address {ret!r} deleted from tracking wallet')

+ 12 - 9
mmgen/tw/common.py

@@ -221,27 +221,31 @@ class TwCommon:
 	async def view_and_sort(self):
 		from ..opts import opt
 		from ..term import get_char
-		self.prompt = type(self).prompt.strip() + '\b'
+		prompt = self.prompt.strip() + '\b'
 		self.no_output = False
 		self.oneshot_msg = None
 		self.interactive = True
+		immed_chars = ''.join(self.key_mappings.keys())
+
+		CUR_RIGHT = lambda n: f'\033[{n}C'
 		CUR_HOME  = '\033[H'
 		ERASE_ALL = '\033[0J'
+		self.cursor_to_end_of_prompt = CUR_RIGHT( len(prompt.split('\n')[-1]) - 2 )
+		clear_screen = '\n\n' if (opt.no_blank or g.test_suite) else CUR_HOME + ERASE_ALL
 
 		while True:
-			msg_r('' if self.no_output else '\n\n' if (opt.no_blank or g.test_suite) else CUR_HOME+ERASE_ALL)
 			reply = get_char(
 				'' if self.no_output else (
-					await self.format_squeezed()
+					clear_screen
+					+ await self.format_squeezed()
 					+ '\n'
 					+ (self.oneshot_msg or '')
-					+ self.prompt
+					+ prompt
 				),
-				immed_chars = ''.join(self.key_mappings.keys())
-			)
+				immed_chars = immed_chars )
 			self.no_output = False
 			self.oneshot_msg = '' if self.oneshot_msg else None # tristate, saves previous state
-			if reply not in self.key_mappings:
+			if reply not in immed_chars:
 				msg_r('\ninvalid keypress ')
 				await asyncio.sleep(0.3)
 				continue
@@ -318,8 +322,7 @@ class TwCommon:
 
 		def post_view(self,parent):
 			if g.platform == 'linux' and parent.oneshot_msg == None:
-				CUR_RIGHT = lambda n: f'\033[{n}C'
-				msg_r(CUR_RIGHT(len(parent.prompt.split('\n')[-1])-2))
+				msg_r(parent.cursor_to_end_of_prompt)
 				parent.no_output = True
 
 	class item_action:

+ 5 - 5
mmgen/tw/ctl.py

@@ -234,9 +234,9 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
 			coinaddr = (await TwAddrData(self.proto)).mmaddr2coinaddr(mmaddr)
 
 		try:
-			if not is_mmgen_id(self.proto,arg1):
-				assert coinaddr, f'Invalid coin address for this chain: {arg1}'
-			assert coinaddr, f'{g.proj_name} address {mmaddr!r} not found in tracking wallet'
+			assert coinaddr, (
+				f'{g.proj_name} address {mmaddr!r} not found in tracking wallet' if mmaddr else
+				f'Invalid coin address for this chain: {addrspec}' )
 			assert await self.is_in_wallet(coinaddr), f'Address {coinaddr!r} not found in tracking wallet'
 		except Exception as e:
 			msg(str(e))
@@ -268,8 +268,8 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
 			return False
 		else:
 			desc = '{} address {} in tracking wallet'.format(
-				mmaddr.type.replace('mmg','MMG'),
-				mmaddr.replace(self.proto.base_coin.lower()+':','') )
+				res.mmaddr.type.replace('mmgen','MMGen'),
+				res.mmaddr.replace(self.proto.base_coin.lower()+':','') )
 			if label:
 				msg(f'Added label {label!r} to {desc}')
 			else:

+ 3 - 3
mmgen/util.py

@@ -176,7 +176,7 @@ def fmt_list(iterable,fmt='dfl',indent=''):
 		'min':       (",",         "'",    "'"),
 		'col':       ('\n'+indent, indent, '' ),
 	}[fmt]
-	return lq + sep.join(iterable) + rq
+	return lq + sep.join(str(i) for i in iterable) + rq
 
 def list_gen(*data):
 	"""
@@ -464,8 +464,8 @@ def make_full_path(outdir,outfile):
 	return os.path.normpath(os.path.join(outdir, os.path.basename(outfile)))
 
 def confirm_or_raise(message,action,expect='YES',exit_msg='Exiting at user request'):
-	if message.strip():
-		msg(message.strip())
+	if message:
+		msg(message)
 	if line_input(
 			(f'{action}  ' if action[0].isupper() else f'Are you sure you want to {action}?\n') +
 			f'Type uppercase {expect!r} to confirm: '

+ 5 - 3
test/test_py_d/ts_regtest.py

@@ -198,8 +198,8 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 		('bob_bal3',                 "Bob's balance"),
 		('bob_pre_import',           'sending to non-imported address'),
 		('generate',                 'mining a block'),
-		('bob_import_addr',          'importing non-MMGen address with --rescan'),
-		('bob_bal4',                 "Bob's balance (after import with rescan)"),
+		('bob_import_addr',          'importing non-MMGen address'),
+		('bob_bal4',                 "Bob's balance (after import)"),
 		('bob_import_list',          'importing flat address list'),
 		('bob_import_list_rescan',   'importing flat address list with --rescan'),
 		('bob_split2',               "splitting Bob's funds"),
@@ -421,7 +421,9 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
 	def bob_import_miner_addr(self):
 		if not self.deterministic:
 			return 'skip'
-		return self.spawn('mmgen-addrimport', [ '--bob', '--rescan', '--quiet', f'--address={self.miner_addr}' ])
+		return self.spawn(
+			'mmgen-addrimport',
+			[ '--bob', '--rescan', '--quiet', f'--address={self.miner_addr}' ] )
 
 	def fund_wallet_deterministic(self,user,addr,utxo_nums,skip_passphrase=False):
 		"""