autosign,xmrwallet: various fixes and cleanups
This commit is contained in:
parent
8e541ebf95
commit
c4f0954614
8 changed files with 83 additions and 66 deletions
|
|
@ -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 []
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue