autosign,xmrwallet: various fixes and cleanups

This commit is contained in:
The MMGen Project 2023-04-18 18:35:58 +00:00
commit c4f0954614
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
8 changed files with 83 additions and 66 deletions

View file

@ -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 []

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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