minor fixes and cleanups

This commit is contained in:
The MMGen Project 2022-05-26 16:07:20 +00:00
commit 3823e8cdc9
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
11 changed files with 63 additions and 60 deletions

View file

@ -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))))

View file

@ -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())

View file

@ -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',

View file

@ -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)

View file

@ -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: Youve chosen the --rescan option. Rescanning the blockchain is
necessary only if an address youre 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(

View file

@ -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):
"""

View file

@ -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')

View file

@ -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:

View file

@ -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:

View file

@ -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: '

View file

@ -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):
"""