whitespace: main_*.py

This commit is contained in:
The MMGen Project 2024-10-18 10:32:07 +00:00
commit 96b6b38c01
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
16 changed files with 380 additions and 373 deletions

View file

@ -22,7 +22,7 @@ mmgen-addrgen: Generate a series or range of addresses from an MMGen
"""
from . import addrlist
from .cfg import gc,Config
from .cfg import gc, Config
from .addr import MMGenAddrType
from .wallet import Wallet
@ -40,7 +40,7 @@ else:
note_addrkey = ''
opts_data = {
'sets': [('print_checksum',True,'quiet',True)],
'sets': [('print_checksum', True, 'quiet', True)],
'text': {
'desc': f"""
Generate a range or list of {gen_desc} from an {gc.proj_name} wallet,
@ -103,66 +103,66 @@ FMT CODES:
"""
},
'code': {
'options': lambda proto,help_notes,cfg,s: s.format(
dmat=help_notes('dfl_mmtype'),
kgs=help_notes('keygen_backends'),
coin_id=help_notes('coin_id'),
dsl=help_notes('dfl_seed_len'),
pnm=gc.proj_name,
what=gen_what,
cfg=cfg,
gc=gc,
'options': lambda proto, help_notes, cfg, s: s.format(
dmat = help_notes('dfl_mmtype'),
kgs = help_notes('keygen_backends'),
coin_id = help_notes('coin_id'),
dsl = help_notes('dfl_seed_len'),
pnm = gc.proj_name,
what = gen_what,
cfg = cfg,
gc = gc,
),
'notes': lambda help_notes,s: s.format(
n_addrkey=note_addrkey,
n_sw=help_notes('subwallet')+'\n\n',
n_pw=help_notes('passwd')+'\n\n',
n_bw=help_notes('brainwallet'),
n_fmt=help_notes('fmt_codes'),
n_at=help_notes('address_types'),
'notes': lambda help_notes, s: s.format(
n_addrkey = note_addrkey,
n_sw = help_notes('subwallet')+'\n\n',
n_pw = help_notes('passwd')+'\n\n',
n_bw = help_notes('brainwallet'),
n_fmt = help_notes('fmt_codes'),
n_at = help_notes('address_types'),
)
}
}
cfg = Config( opts_data=opts_data, opt_filter=opt_filter, need_amt=False )
cfg = Config(opts_data=opts_data, opt_filter=opt_filter, need_amt=False)
proto = cfg._proto
addr_type = MMGenAddrType(
proto = proto,
id_str = cfg.type or proto.dfl_mmtype,
errmsg = f'{cfg.type!r}: invalid parameter for --type option' )
errmsg = f'{cfg.type!r}: invalid parameter for --type option')
if len(cfg._args) < 1:
cfg._usage()
if cfg.keygen_backend:
from .keygen import check_backend
check_backend( cfg, proto, cfg.keygen_backend, cfg.type )
check_backend(cfg, proto, cfg.keygen_backend, cfg.type)
idxs = addrlist.AddrIdxList( fmt_str=cfg._args.pop() )
idxs = addrlist.AddrIdxList(fmt_str=cfg._args.pop())
from .fileutil import get_seed_file
sf = get_seed_file(cfg,1)
sf = get_seed_file(cfg, 1)
from .ui import do_license_msg
do_license_msg(cfg)
ss = Wallet(cfg,sf)
ss = Wallet(cfg, sf)
ss_seed = ss.seed if cfg.subwallet is None else ss.seed.subseed(cfg.subwallet,print_msg=True)
ss_seed = ss.seed if cfg.subwallet is None else ss.seed.subseed(cfg.subwallet, print_msg=True)
if cfg.no_addresses:
gen_clsname = 'KeyList'
elif cfg.viewkeys:
gen_clsname = 'ViewKeyAddrList'
al = getattr( addrlist, gen_clsname )(
al = getattr(addrlist, gen_clsname)(
cfg = cfg,
proto = proto,
seed = ss_seed,
addr_idxs = idxs,
mmtype = addr_type )
mmtype = addr_type)
af = al.file
@ -170,13 +170,13 @@ af.format()
if al.gen_addrs and cfg.print_checksum:
from .util import Die
Die(0,al.checksum)
Die(0, al.checksum)
from .ui import keypress_confirm
if al.gen_keys and keypress_confirm( cfg, 'Encrypt key list?' ):
if al.gen_keys and keypress_confirm(cfg, 'Encrypt key list?'):
af.encrypt()
af.write(
binary = True,
desc = f'encrypted {af.desc}' )
desc = f'encrypted {af.desc}')
else:
af.write()

View file

@ -22,9 +22,9 @@ mmgen-addrimport: Import addresses into a MMGen coin daemon tracking wallet
from collections import namedtuple
from .cfg import gc,Config
from .util import msg,suf,die,fmt,async_run
from .addrlist import AddrList,KeyAddrList
from .cfg import gc, Config
from .util import msg, suf, die, fmt, async_run
from .addrlist import AddrList, KeyAddrList
opts_data = {
'text': {
@ -81,18 +81,18 @@ addrimport_msgs = {
"""
}
def parse_cmd_args(rpc,cmd_args):
def parse_cmd_args(rpc, cmd_args):
def import_mmgen_list(infile):
al = (AddrList,KeyAddrList)[bool(cfg.keyaddr_file)](cfg,proto,infile)
if al.al_id.mmtype in ('S','B'):
al = (AddrList, KeyAddrList)[bool(cfg.keyaddr_file)](cfg, proto, infile)
if al.al_id.mmtype in ('S', 'B'):
if not rpc.info('segwit_is_active'):
die(2,'Segwit is not active on this chain. Cannot import Segwit addresses')
die(2, 'Segwit is not active on this chain. Cannot import Segwit addresses')
return al
if len(cmd_args) == 1:
infile = cmd_args[0]
from .fileutil import check_infile,get_lines_from_file
from .fileutil import check_infile, get_lines_from_file
check_infile(infile)
if cfg.addrlist:
al = AddrList(
@ -102,16 +102,16 @@ def parse_cmd_args(rpc,cmd_args):
cfg,
infile,
f'non-{gc.proj_name} addresses',
trim_comments = True ) )
trim_comments = True))
else:
al = import_mmgen_list(infile)
elif len(cmd_args) == 0 and cfg.address:
al = AddrList( cfg, proto=proto, addrlist=[cfg.address] )
al = AddrList(cfg, proto=proto, addrlist=[cfg.address])
infile = 'command line'
else:
die(1,addrimport_msgs['bad_args'])
die(1, addrimport_msgs['bad_args'])
return al,infile
return al, infile
def check_opts(twctl):
batch = bool(cfg.batch)
@ -126,14 +126,14 @@ def check_opts(twctl):
if not keypress_confirm(
cfg,
f'\n{addrimport_msgs["rescan"]}\n\nContinue?',
default_yes = True ):
die(1,'Exiting at user request')
default_yes = True):
die(1, 'Exiting at user request')
if batch and not 'batch' in twctl.caps:
msg(f"‘--batch’ ignored: not supported by {type(twctl).__name__}")
batch = False
return batch,rescan
return batch, rescan
async def main():
from .tw.ctl import TwCtl
@ -144,44 +144,44 @@ async def main():
cfg = cfg,
proto = proto,
token_addr = cfg.token_addr,
mode = 'i' )
mode = 'i')
if cfg.token or cfg.token_addr:
msg(f'Importing for token {twctl.token.hl(0)} ({twctl.token.hlc(proto.tokensym)})')
for k,v in addrimport_msgs.items():
addrimport_msgs[k] = fmt(v,indent=' ',strip_char='\t').rstrip()
for k, v in addrimport_msgs.items():
addrimport_msgs[k] = fmt(v, indent=' ', strip_char='\t').rstrip()
al, infile = parse_cmd_args(twctl.rpc, cfg._args)
cfg._util.qmsg(
f'OK. {al.num_addrs} addresses'
+ (f' from Seed ID {al.al_id.sid.hl()}' if hasattr(al.al_id,'sid') else '') )
+ (f' from Seed ID {al.al_id.sid.hl()}' if hasattr(al.al_id, 'sid') else ''))
msg(
f'Importing {len(al.data)} address{suf(al.data,"es")} from {infile}'
+ (' (batch mode)' if cfg.batch else '') )
f'Importing {len(al.data)} address{suf(al.data, "es")} from {infile}'
+ (' (batch mode)' if cfg.batch else ''))
batch,rescan = check_opts(twctl)
batch, rescan = check_opts(twctl)
def gen_args_list(al):
_d = namedtuple('import_data',['addr','twmmid','comment'])
_d = namedtuple('import_data', ['addr', 'twmmid', 'comment'])
for e in al.data:
yield _d(
addr = e.addr,
twmmid = f'{al.al_id}:{e.idx}' if e.idx else f'{proto.base_coin.lower()}:{e.addr}',
comment = e.comment )
comment = e.comment)
args_list = list(gen_args_list(al))
await twctl.import_address_common( args_list, batch=batch )
await twctl.import_address_common(args_list, batch=batch)
if rescan:
await twctl.rescan_addresses({a.addr for a in args_list})
del twctl
cfg = Config( opts_data=opts_data, need_amt=False )
cfg = Config(opts_data=opts_data, need_amt=False)
proto = cfg._proto

View file

@ -22,7 +22,7 @@ autosign: Auto-sign MMGen transactions, message files and XMR wallet output file
import sys
from .util import msg,die,fmt_list,exit_if_mswin,async_run
from .util import msg, die, fmt_list, exit_if_mswin, async_run
exit_if_mswin('autosigning')
@ -160,7 +160,7 @@ is over.
'code': {
'options': lambda s: s.format(
asi = asi,
mn_fmts = fmt_list( asi.mn_fmts, fmt='no_spc' ),
mn_fmts = fmt_list(asi.mn_fmts, fmt='no_spc'),
),
'notes': lambda s: s.format(asi=asi)
}
@ -197,19 +197,19 @@ cfg = Config(
cmd = cfg._args[0] if len(cfg._args) == 1 else 'sign' if not cfg._args else cfg._usage()
if cmd not in Autosign.cmds + Autosign.util_cmds:
die(1,f'{cmd}’: unrecognized command')
die(1, f'{cmd}’: unrecognized command')
if cmd != 'setup':
for opt in ('seed_len', 'mnemonic_fmt'):
if getattr(cfg,opt):
die(1, f'--{opt.replace("_","-")} makes sense only for the ‘setup’ operation')
if getattr(cfg, opt):
die(1, f'--{opt.replace("_", "-")} makes sense only for the ‘setup’ operation')
if cmd not in ('sign', 'wait'):
for opt in ('no_summary', 'led', 'stealth_led', 'full_summary'):
if getattr(cfg,opt):
die(1, f'--{opt.replace("_","-")} makes no sense for the ‘{cmd}’ operation')
if getattr(cfg, opt):
die(1, f'--{opt.replace("_", "-")} makes no sense for the ‘{cmd}’ operation')
asi = Autosign(cfg,cmd)
asi = Autosign(cfg, cmd)
cfg._post_init()
@ -218,13 +218,13 @@ if cmd == 'gen_key':
elif cmd == 'setup':
asi.setup()
from .ui import keypress_confirm
if cfg.xmrwallets and keypress_confirm( cfg, '\nContinue with Monero setup?', default_yes=True ):
if cfg.xmrwallets and keypress_confirm(cfg, '\nContinue with Monero setup?', default_yes=True):
msg('')
asi.xmr_setup()
asi.do_umount()
elif cmd == 'xmr_setup':
if not cfg.xmrwallets:
die(1,'Please specify a wallet or range of wallets with the --xmrwallets option')
die(1, 'Please specify a wallet or range of wallets with the --xmrwallets option')
asi.do_mount()
asi.xmr_setup()
asi.do_umount()

View file

@ -15,7 +15,7 @@ mmgen-msg: Message signing operations for the MMGen suite
import sys
from .cfg import Config
from .base_obj import AsyncInit
from .util import msg,suf,async_run,die
from .util import msg, suf, async_run, die
from .msg import (
NewMsg,
UnsignedMsg,
@ -25,11 +25,11 @@ from .msg import (
)
class MsgOps:
ops = ('create','sign','verify')
ops = ('create', 'sign', 'verify')
class create:
def __init__(self,msg,addr_specs):
def __init__(self, msg, addr_specs):
NewMsg(
cfg = cfg,
coin = cfg._proto.coin,
@ -37,35 +37,35 @@ class MsgOps:
message = msg,
addrlists = addr_specs,
msghash_type = cfg.msghash_type
).write_to_file( ask_overwrite=False )
).write_to_file(ask_overwrite=False)
class sign(metaclass=AsyncInit):
async def __init__(self,msgfile,wallet_files):
async def __init__(self, msgfile, wallet_files):
m = UnsignedMsg( cfg, infile=msgfile )
m = UnsignedMsg(cfg, infile=msgfile)
if not wallet_files:
from .filename import find_file_in_dir
from .wallet import get_wallet_cls
wallet_files = [find_file_in_dir( get_wallet_cls('mmgen'), cfg.data_dir )]
wallet_files = [find_file_in_dir(get_wallet_cls('mmgen'), cfg.data_dir)]
await m.sign(wallet_files)
m = SignedMsg( cfg, data=m.__dict__ )
m = SignedMsg(cfg, data=m.__dict__)
m.write_to_file( ask_overwrite=False )
m.write_to_file(ask_overwrite=False)
if m.data.get('failed_sids'):
sys.exit(1)
class verify(sign):
async def __init__(self,msgfile,addr=None):
async def __init__(self, msgfile, addr=None):
try:
m = SignedOnlineMsg( cfg, infile=msgfile )
m = SignedOnlineMsg(cfg, infile=msgfile)
except:
m = ExportedMsgSigs( cfg, infile=msgfile )
m = ExportedMsgSigs(cfg, infile=msgfile)
nSigs = await m.verify(addr)
@ -81,14 +81,14 @@ class MsgOps:
class export(sign):
async def __init__(self,msgfile,addr=None):
async def __init__(self, msgfile, addr=None):
from .fileutil import write_data_to_file
write_data_to_file(
cfg = cfg,
outfile = 'signatures.json',
data = SignedOnlineMsg( cfg, infile=msgfile ).get_json_for_export( addr ),
desc = 'signature data' )
data = SignedOnlineMsg(cfg, infile=msgfile).get_json_for_export(addr),
desc = 'signature data')
opts_data = {
'text': {
@ -196,13 +196,13 @@ $ mmgen-msg verify signatures.json
"""
},
'code': {
'notes': lambda help_notes,s: s.format(
n_at=help_notes('address_types'),
'notes': lambda help_notes, s: s.format(
n_at = help_notes('address_types'),
)
}
}
cfg = Config( opts_data=opts_data, need_amt=False )
cfg = Config(opts_data=opts_data, need_amt=False)
cmd_args = cfg._args
@ -212,22 +212,22 @@ if len(cmd_args) < 2:
op = cmd_args.pop(0)
if cfg.msghash_type and op != 'create':
die(1,'--msghash-type option may only be used with the "create" command')
die(1, '--msghash-type option may only be used with the "create" command')
async def main():
if op == 'create':
if len(cmd_args) < 2:
cfg._usage()
MsgOps.create( cmd_args[0], ' '.join(cmd_args[1:]) )
MsgOps.create(cmd_args[0], ' '.join(cmd_args[1:]))
elif op == 'sign':
if len(cmd_args) < 1:
cfg._usage()
await MsgOps.sign( cmd_args[0], cmd_args[1:] )
elif op in ('verify','export'):
if len(cmd_args) not in (1,2):
await MsgOps.sign(cmd_args[0], cmd_args[1:])
elif op in ('verify', 'export'):
if len(cmd_args) not in (1, 2):
cfg._usage()
await getattr(MsgOps,op)( cmd_args[0], cmd_args[1] if len(cmd_args) == 2 else None )
await getattr(MsgOps, op)(cmd_args[0], cmd_args[1] if len(cmd_args) == 2 else None)
else:
die(1,f'{op!r}: unrecognized operation')
die(1, f'{op!r}: unrecognized operation')
async_run(main())

View file

@ -21,9 +21,9 @@ mmgen-passgen: Generate a series or range of passwords from an MMGen
deterministic wallet
"""
import sys,time
import sys, time
from .cfg import gc,Config
from .cfg import gc, Config
from .addrlist import AddrIdxList
from .passwdlist import PasswordList
from .wallet import Wallet
@ -33,7 +33,7 @@ from .ui import keypress_confirm
pwi = PasswordList.pw_info
opts_data = {
'sets': [('print_checksum',True,'quiet',True)],
'sets': [('print_checksum', True, 'quiet', True)],
'text': {
'desc': f"""
Generate a range or list of passwords from an {gc.proj_name} wallet,
@ -116,21 +116,24 @@ FMT CODES:
"""
},
'code': {
'options': lambda cfg,help_notes,s: s.format(
cfg=cfg,
dsl=help_notes('dfl_seed_len'),
pl=PasswordList,
gc=gc,
'options': lambda cfg, help_notes, s: s.format(
cfg = cfg,
dsl = help_notes('dfl_seed_len'),
pl = PasswordList,
gc = gc,
),
'notes': lambda cfg,help_notes,s: s.format(
cfg=cfg,i58=pwi['b58'],i32=pwi['b32'],i39=pwi['bip39'],
ml=MMGenPWIDString.max_len,
fs="', '".join(MMGenPWIDString.forbidden),
n_pw=help_notes('passwd'),
n_bw=help_notes('brainwallet'),
pfi=help_notes('password_formats'),
n_fmt=help_notes('fmt_codes'),
gc=gc,
'notes': lambda cfg, help_notes, s: s.format(
cfg = cfg,
i58 = pwi['b58'],
i32 = pwi['b32'],
i39 = pwi['bip39'],
ml = MMGenPWIDString.max_len,
fs = '", "'.join(MMGenPWIDString.forbidden),
n_pw = help_notes('passwd'),
n_bw = help_notes('brainwallet'),
pfi = help_notes('password_formats'),
n_fmt = help_notes('fmt_codes'),
gc = gc,
)
}
}
@ -145,13 +148,13 @@ pw_idxs = AddrIdxList(fmt_str=cfg._args.pop())
pw_id_str = cfg._args.pop()
from .fileutil import get_seed_file
sf = get_seed_file(cfg,1)
sf = get_seed_file(cfg, 1)
pw_fmt = cfg.passwd_fmt or PasswordList.dfl_pw_fmt
pw_len = pwi[pw_fmt].dfl_len // 2 if cfg.passwd_len in ('h','H') else cfg.passwd_len
pw_len = pwi[pw_fmt].dfl_len // 2 if cfg.passwd_len in ('h', 'H') else cfg.passwd_len
from .protocol import init_proto
proto = init_proto( cfg, 'btc' ) # TODO: get rid of dummy proto
proto = init_proto(cfg, 'btc') # TODO: get rid of dummy proto
PasswordList(
cfg = cfg,
@ -159,12 +162,12 @@ PasswordList(
pw_id_str = pw_id_str,
pw_len = pw_len,
pw_fmt = pw_fmt,
chk_params_only = True )
chk_params_only = True)
from .ui import do_license_msg
do_license_msg(cfg)
ss = Wallet(cfg,sf)
ss = Wallet(cfg, sf)
al = PasswordList(
cfg = cfg,
@ -173,15 +176,15 @@ al = PasswordList(
pw_idxs = pw_idxs,
pw_id_str = pw_id_str,
pw_len = pw_len,
pw_fmt = pw_fmt )
pw_fmt = pw_fmt)
af = al.file
af.format()
if keypress_confirm( cfg, 'Encrypt password list?' ):
if keypress_confirm(cfg, 'Encrypt password list?'):
af.encrypt()
af.write(binary=True,desc='encrypted password list')
af.write(binary=True, desc='encrypted password list')
else:
if cfg.test_suite_popen_spawn and sys.platform == 'win32':
time.sleep(0.1)

View file

@ -21,8 +21,8 @@ mmgen-regtest: Coin daemon regression test mode setup and operations for the MMG
suite
"""
from .cfg import gc,Config
from .util import die,async_run
from .cfg import gc, Config
from .util import die, async_run
opts_data = {
'sets': [('yes', True, 'quiet', True)],
@ -64,7 +64,7 @@ cmd_args = cfg._args
from .proto.btc.regtest import MMGenRegtest
def check_num_args():
m = getattr(MMGenRegtest,cmd_args[0])
m = getattr(MMGenRegtest, cmd_args[0])
margs = m.__code__.co_varnames[1:m.__code__.co_argcount]
mdfls = m.__defaults__ or ()
amin = len(margs) - len(mdfls)
@ -72,15 +72,15 @@ def check_num_args():
args = cmd_args[1:]
m = "{}: too {} arguments for command '%s' (must have no {} than {})" % cmd_args[0]
if len(args) < amin:
die(1,m.format(args,'few','less',amin))
die(1, m.format(args, 'few', 'less', amin))
elif len(cmd_args[1:]) > amax:
die(1,m.format(args,'many','more',amax))
die(1, m.format(args, 'many', 'more', amax))
if not cmd_args:
cfg._usage()
elif cmd_args[0] not in MMGenRegtest.usr_cmds:
die(1,f'{cmd_args[0]!r}: invalid command')
elif cmd_args[0] not in ('cli','wallet_cli','balances'):
die(1, f'{cmd_args[0]!r}: invalid command')
elif cmd_args[0] not in ('cli', 'wallet_cli', 'balances'):
check_num_args()
async def main():

View file

@ -21,11 +21,11 @@ mmgen-seedjoin: Regenerate an MMGen deterministic wallet from seed shares
created by 'mmgen-seedsplit'
"""
from .cfg import gc,Config
from .util import msg,msg_r,die
from .cfg import gc, Config
from .util import msg, msg_r, die
from .color import yellow
from .seed import Seed
from .seedsplit import SeedSplitIDString,MasterShareIdx,SeedShareMasterJoining
from .seedsplit import SeedSplitIDString, MasterShareIdx, SeedShareMasterJoining
from .wallet import Wallet
opts_data = {
@ -79,21 +79,22 @@ FMT CODES:
"""
},
'code': {
'options': lambda cfg,s: s.format(
ms_min=MasterShareIdx.min_val,
ms_max=MasterShareIdx.max_val,
cfg=cfg,
gc=gc,
'options': lambda cfg, s: s.format(
ms_min = MasterShareIdx.min_val,
ms_max = MasterShareIdx.max_val,
cfg = cfg,
gc = gc,
),
'notes': lambda cfg,help_notes,s: s.format(
f=help_notes('fmt_codes'),
n_pw=help_notes('passwd'),
'notes': lambda cfg, help_notes, s: s.format(
f = help_notes('fmt_codes'),
n_pw = help_notes('passwd'),
)
}
}
def print_shares_info():
si,out = 0,'\nComputed shares:\n'
si = 0
out = '\nComputed shares:\n'
if cfg.master_share:
fs = '{:3}: {}->{} ' + yellow('(master share #{}, split id ') + '{}' + yellow(', share count {})\n')
out += fs.format(
@ -102,9 +103,9 @@ def print_shares_info():
share1.sid,
master_idx,
id_str.hl2(encl='‘’'),
len(shares) )
len(shares))
si = 1
for n,s in enumerate(shares[si:],si+1):
for n, s in enumerate(shares[si:],si+1):
out += f'{n:3}: {s.sid}\n'
cfg._util.qmsg(out)
@ -135,7 +136,7 @@ shares = [Wallet(cfg).seed] if cfg.hidden_incog_input_params else []
shares += [Wallet(cfg,fn).seed for fn in cfg._args]
if cfg.master_share:
share1 = SeedShareMasterJoining( cfg, master_idx, shares[0], id_str, len(shares) ).derived_seed
share1 = SeedShareMasterJoining(cfg, master_idx, shares[0], id_str, len(shares)).derived_seed
else:
share1 = shares[0]
@ -143,7 +144,7 @@ print_shares_info()
msg_r('Joining {n}-of-{n} XOR split...'.format(n=len(shares)))
seed_out = Seed.join_shares( cfg, [share1] + shares[1:] )
seed_out = Seed.join_shares(cfg, [share1] + shares[1:])
msg(f'OK\nJoined Seed ID: {seed_out.sid.hl()}')

View file

@ -23,8 +23,8 @@ mmgen-split: Split funds after a replayable chain fork using a timelocked transa
UNMAINTAINED
"""
from .cfg import Config,gc
from .util import gmsg,die
from .cfg import Config, gc
from .util import gmsg, die
opts_data = {
'text': {
@ -80,43 +80,43 @@ transaction reconfirmed before the timelock expires. Use at your own risk.
"""
},
'code': {
'options': lambda proto,s: s.format(
oc=proto.forks[-1][2].upper(),
bh='current block height'),
'options': lambda proto, s: s.format(
oc = proto.forks[-1][2].upper(),
bh = 'current block height'),
}
}
cfg = Config( opts_data=opts_data, need_amt=False )
cfg = Config(opts_data=opts_data, need_amt=False)
proto = cfg._proto
die(1,'This command is disabled')
die(1, 'This command is disabled')
# the following code is broken:
cfg.other_coin = cfg.other_coin.upper() if cfg.other_coin else proto.forks[-1][2].upper()
if cfg.other_coin.lower() not in [e[2] for e in proto.forks if e[3] is True]:
die(1,f'{cfg.other_coin!r}: not a replayable fork of {proto.coin} chain')
die(1, f'{cfg.other_coin!r}: not a replayable fork of {proto.coin} chain')
if len(cfg._args) != 2:
die(1,f'This command requires exactly two {gc.proj_name} addresses as arguments')
die(1, f'This command requires exactly two {gc.proj_name} addresses as arguments')
from .addr import MMGenID
try:
mmids = [MMGenID(proto,a) for a in cfg._args]
mmids = [MMGenID(proto, a) for a in cfg._args]
except:
die(1,'Command line arguments must be valid MMGen IDs')
die(1, 'Command line arguments must be valid MMGen IDs')
if mmids[0] == mmids[1]:
die(2,f'Both transactions have the same output! ({mmids[0]})')
die(2, f'Both transactions have the same output! ({mmids[0]})')
from .tx import MMGenSplitTX
from .protocol import init_proto
if cfg.tx_fees:
for idx,g_coin in ((1,cfg.other_coin),(0,proto.coin)):
proto = init_proto( cfg, g_coin )
for idx, g_coin in ((1, cfg.other_coin), (0, proto.coin)):
proto = init_proto(cfg, g_coin)
cfg.fee = cfg.tx_fees.split(',')[idx]
# opts.opt_is_tx_fee('foo',cfg.fee,'transaction fee') # raises exception on error
# opts.opt_is_tx_fee('foo', cfg.fee, 'transaction fee') # raises exception on error
tx1 = MMGenSplitTX(proto)
cfg.no_blank = True
@ -128,14 +128,14 @@ async def main():
from .rpc import rpc_init
rpc = rpc_init(proto)
locktime = rpc.call('getblockcount')
tx1.create(mmids[0],locktime)
tx1.create(mmids[0], locktime)
tx1.format()
tx1.create_fn()
gmsg(f'\nCreating transaction for short chain ({cfg.other_coin})')
proto2 = init_proto( cfg, cfg.other_coin )
proto2 = init_proto(cfg, cfg.other_coin)
tx2 = MMGenSplitTX(proto2)
tx2.inputs = tx1.inputs
@ -143,6 +143,6 @@ async def main():
tx2.create_split(mmids[1])
for tx,desc in ((tx1,'Long chain (timelocked)'),(tx2,'Short chain')):
for tx, desc in ((tx1, 'Long chain (timelocked)'), (tx2, 'Short chain')):
tx.desc = desc + ' transaction'
tx.file.write(ask_write=False,ask_overwrite=not cfg.yes,ask_write_default_yes=False)
tx.file.write(ask_write=False, ask_overwrite=not cfg.yes, ask_write_default_yes=False)

View file

@ -21,9 +21,9 @@ mmgen-tool: Perform various MMGen- and cryptocoin-related operations.
Part of the MMGen suite
"""
import sys,os,importlib
from .cfg import gc,Config
from .util import msg,Msg,die,capfirst,suf,async_run
import sys, os, importlib
from .cfg import gc, Config
from .util import msg, Msg, die, capfirst, suf, async_run
opts_data = {
'text': {
@ -59,15 +59,15 @@ Type ‘{pn} help <command>’ for help on a particular command
"""
},
'code': {
'options': lambda cfg,s, help_notes: s.format(
kgs=help_notes('keygen_backends'),
coin_id=help_notes('coin_id'),
cfg=cfg,
gc=gc,
'options': lambda cfg, s, help_notes: s.format(
kgs = help_notes('keygen_backends'),
coin_id = help_notes('coin_id'),
cfg = cfg,
gc = gc,
),
'notes': lambda cfg,s, help_notes: s.format(
ch=help_notes('tool_help'),
pn=gc.prog_name)
'notes': lambda cfg, s, help_notes: s.format(
ch = help_notes('tool_help'),
pn = gc.prog_name)
}
}
@ -177,16 +177,16 @@ mods = {
}
def get_cmds():
return [cmd for mod,cmds in mods.items() if mod != 'help' for cmd in cmds]
return [cmd for mod, cmds in mods.items() if mod != 'help' for cmd in cmds]
def create_call_sig(cmd,cls,as_string=False):
def create_call_sig(cmd, cls, as_string=False):
m = getattr(cls,cmd)
m = getattr(cls, cmd)
if 'varargs_call_sig' in m.__code__.co_varnames: # hack
flag = 'VAR_ARGS'
va = m.__defaults__[0]
args,dfls,ann = va['args'],va['dfls'],va['annots']
args, dfls, ann = va['args'], va['dfls'], va['annots']
else:
flag = None
args = m.__code__.co_varnames[1:m.__code__.co_argcount]
@ -195,25 +195,25 @@ def create_call_sig(cmd,cls,as_string=False):
nargs = len(args) - len(dfls)
dfl_types = tuple(
ann[a] if a in ann and isinstance(ann[a],type) else type(dfls[i])
for i,a in enumerate(args[nargs:]) )
ann[a] if a in ann and isinstance(ann[a], type) else type(dfls[i])
for i, a in enumerate(args[nargs:]))
if as_string:
get_type_from_ann = lambda x: 'str or STDIN' if ann[x] == 'sstr' else ann[x].__name__
return ' '.join(
[f'{a} [{get_type_from_ann(a)}]' for a in args[:nargs]] +
[f'{a} [{dfl_types[n].__name__}={dfls[n]!r}]' for n,a in enumerate(args[nargs:])] )
[f'{a} [{dfl_types[n].__name__}={dfls[n]!r}]' for n, a in enumerate(args[nargs:])])
else:
get_type_from_ann = lambda x: 'str' if ann[x] == 'sstr' else ann[x].__name__
return (
[(a,get_type_from_ann(a)) for a in args[:nargs]], # c_args
{a:dfls[n] for n,a in enumerate(args[nargs:])}, # c_kwargs
{a:dfl_types[n] for n,a in enumerate(args[nargs:])}, # c_kwargs_types
[(a, get_type_from_ann(a)) for a in args[:nargs]], # c_args
{a:dfls[n] for n, a in enumerate(args[nargs:])}, # c_kwargs
{a:dfl_types[n] for n, a in enumerate(args[nargs:])}, # c_kwargs_types
('STDIN_OK' if nargs and ann[args[0]] == 'sstr' else flag), # flag
ann ) # ann
ann) # ann
def process_args(cmd,cmd_args,cls):
c_args,c_kwargs,c_kwargs_types,flag,_ = create_call_sig(cmd,cls)
def process_args(cmd, cmd_args, cls):
c_args, c_kwargs, c_kwargs_types, flag, _ = create_call_sig(cmd, cls)
have_stdin_input = False
def usage_die(s):
@ -230,31 +230,31 @@ def process_args(cmd,cmd_args,cls):
# If we're reading from a pipe, replace '-' with output of previous command
if flag == 'STDIN_OK' and u_args and u_args[0] == '-':
if sys.stdin.isatty():
die( 'BadFilename', "Standard input is a TTY. Can't use '-' as a filename" )
die('BadFilename', "Standard input is a TTY. Can't use '-' as a filename")
else:
from .util2 import parse_bytespec
max_dlen_spec = '10kB' # limit input to 10KB for now
max_dlen = parse_bytespec(max_dlen_spec)
u_args[0] = os.read(0,max_dlen)
u_args[0] = os.read(0, max_dlen)
have_stdin_input = True
if len(u_args[0]) >= max_dlen:
die(2,f'Maximum data input for this command is {max_dlen_spec}')
die(2, f'Maximum data input for this command is {max_dlen_spec}')
if not u_args[0]:
die(2,f'{cmd}: ERROR: no output from previous command in pipe')
die(2, f'{cmd}: ERROR: no output from previous command in pipe')
u_nkwargs = len(cmd_args) - len(c_args)
u_kwargs = {}
if flag == 'VAR_ARGS':
cmd_args = ['dummy_arg'] + cmd_args
t = [a.split('=',1) for a in cmd_args if '=' in a]
t = [a.split('=', 1) for a in cmd_args if '=' in a]
tk = [a[0] for a in t]
tk_bad = [a for a in tk if a not in c_kwargs]
if set(tk_bad) != set(tk[:len(tk_bad)]): # permit non-kw args to contain '='
die(1,f'{tk_bad[-1]!r}: illegal keyword argument')
die(1, f'{tk_bad[-1]!r}: illegal keyword argument')
u_kwargs = dict(t[len(tk_bad):])
u_args = cmd_args[:-len(u_kwargs) or None]
elif u_nkwargs > 0:
u_kwargs = dict([a.split('=',1) for a in cmd_args[len(c_args):] if '=' in a])
u_kwargs = dict([a.split('=', 1) for a in cmd_args[len(c_args):] if '=' in a])
if len(u_kwargs) != u_nkwargs:
usage_die(f'Command requires exactly {len(c_args)} non-keyword argument{suf(c_args)}')
if len(u_kwargs) > len(c_kwargs):
@ -264,20 +264,20 @@ def process_args(cmd,cmd_args,cls):
if k not in c_kwargs:
usage_die(f'{k!r}: invalid keyword argument')
def conv_type(arg,arg_name,arg_type):
if arg_type == 'bytes' and not isinstance(arg,bytes):
die(1,"'Binary input data must be supplied via STDIN")
def conv_type(arg, arg_name, arg_type):
if arg_type == 'bytes' and not isinstance(arg, bytes):
die(1, "'Binary input data must be supplied via STDIN")
if have_stdin_input and arg_type == 'str' and isinstance(arg,bytes):
if have_stdin_input and arg_type == 'str' and isinstance(arg, bytes):
NL = '\r\n' if sys.platform == 'win32' else '\n'
arg = arg.decode()
if arg[-len(NL):] == NL: # rstrip one newline
arg = arg[:-len(NL)]
if arg_type == 'bool':
if arg.lower() in ('true','yes','1','on'):
if arg.lower() in ('true', 'yes', '1', 'on'):
arg = True
elif arg.lower() in ('false','no','0','off'):
elif arg.lower() in ('false', 'no', '0', 'off'):
arg = False
else:
usage_die(f'{arg!r}: invalid boolean value for keyword argument')
@ -285,17 +285,17 @@ def process_args(cmd,cmd_args,cls):
try:
return __builtins__[arg_type](arg)
except:
die(1,f'{arg!r}: Invalid argument for argument {arg_name} ({arg_type!r} required)')
die(1, f'{arg!r}: Invalid argument for argument {arg_name} ({arg_type!r} required)')
if flag == 'VAR_ARGS':
args = [conv_type(u_args[i],c_args[0][0],c_args[0][1]) for i in range(len(u_args))]
args = [conv_type(u_args[i], c_args[0][0], c_args[0][1]) for i in range(len(u_args))]
else:
args = [conv_type(u_args[i],c_args[i][0],c_args[i][1]) for i in range(len(c_args))]
kwargs = {k:conv_type(v,k,c_kwargs_types[k].__name__) for k,v in u_kwargs.items()}
args = [conv_type(u_args[i], c_args[i][0], c_args[i][1]) for i in range(len(c_args))]
kwargs = {k:conv_type(v, k, c_kwargs_types[k].__name__) for k, v in u_kwargs.items()}
return ( args, kwargs )
return (args, kwargs)
def process_result(ret,pager=False,print_result=False):
def process_result(ret, pager=False, print_result=False):
"""
Convert result to something suitable for output to screen and return it.
If result is bytes and not convertible to utf8, output as binary using os.write().
@ -315,43 +315,43 @@ def process_result(ret,pager=False,print_result=False):
if ret is True:
return True
elif ret in (False,None):
die(2,f'tool command returned {ret!r}')
elif isinstance(ret,str):
elif ret in (False, None):
die(2, f'tool command returned {ret!r}')
elif isinstance(ret, str):
return triage_result(ret)
elif isinstance(ret,int):
elif isinstance(ret, int):
return triage_result(str(ret))
elif isinstance(ret,tuple):
return triage_result('\n'.join([r.decode() if isinstance(r,bytes) else r for r in ret]))
elif isinstance(ret,bytes):
elif isinstance(ret, tuple):
return triage_result('\n'.join([r.decode() if isinstance(r, bytes) else r for r in ret]))
elif isinstance(ret, bytes):
try:
return triage_result(ret.decode())
except:
# don't add NL to binary data if it can't be converted to utf8
return os.write(1,ret) if print_result else ret
return os.write(1, ret) if print_result else ret
else:
die(2,f'tool.py: can’t handle return value of type {type(ret).__name__!r}')
die(2, f'tool.py: can’t handle return value of type {type(ret).__name__!r}')
def get_cmd_cls(cmd):
for modname,cmdlist in mods.items():
for modname, cmdlist in mods.items():
if cmd in cmdlist:
return getattr(importlib.import_module(f'mmgen.tool.{modname}'),'tool_cmd')
return getattr(importlib.import_module(f'mmgen.tool.{modname}'), 'tool_cmd')
return False
def get_mod_cls(modname):
return getattr(importlib.import_module(f'mmgen.tool.{modname}'),'tool_cmd')
return getattr(importlib.import_module(f'mmgen.tool.{modname}'), 'tool_cmd')
if gc.prog_name.endswith('-tool'):
cfg = Config( opts_data=opts_data, parse_only=True )
cfg = Config(opts_data=opts_data, parse_only=True)
po = cfg._parsed_opts
if po.user_opts.get('list'):
def gen():
for mod,cmdlist in mods.items():
for mod, cmdlist in mods.items():
if mod == 'help':
continue
yield capfirst( get_mod_cls(mod).__doc__.lstrip().split('\n')[0] ) + ':'
yield capfirst(get_mod_cls(mod).__doc__.lstrip().split('\n')[0]) + ':'
for cmd in cmdlist:
yield ' ' + cmd
yield ''
@ -366,23 +366,23 @@ if gc.prog_name.endswith('-tool'):
cls = get_cmd_cls(cmd)
if not cls:
die(1,f'{cmd!r}: no such command')
die(1, f'{cmd!r}: no such command')
cfg = Config(
opts_data = opts_data,
parsed_opts = po,
need_proto = cls.need_proto,
init_opts = {'rpc_backend':'aiohttp'} if cmd == 'twimport' else None,
process_opts = True )
process_opts = True)
cmd,*args = cfg._args
cmd, *args = cfg._args
if cmd in ('help','usage') and args:
if cmd in ('help', 'usage') and args:
args[0] = 'command_name=' + args[0]
args,kwargs = process_args(cmd,args,cls)
args, kwargs = process_args(cmd, args, cls)
ret = getattr(cls(cfg,cmdname=cmd),cmd)(*args,**kwargs)
ret = getattr(cls(cfg, cmdname=cmd), cmd)(*args, **kwargs)
if type(ret).__name__ == 'coroutine':
ret = async_run(ret)
@ -390,4 +390,4 @@ if gc.prog_name.endswith('-tool'):
process_result(
ret,
pager = kwargs.get('pager'),
print_result = True )
print_result = True)

View file

@ -21,8 +21,8 @@ mmgen-txbump: Increase the fee on a replaceable (replace-by-fee) MMGen
transaction, and optionally sign and send it
"""
from .cfg import gc,Config
from .util import msg,msg_r,die,async_run
from .cfg import gc, Config
from .util import msg, msg_r, die, async_run
from .color import green
opts_data = {
@ -80,7 +80,7 @@ opts_data = {
-z, --show-hash-presets Show information on available hash presets
""",
'notes': """
{}{}
{e}{s}
Seed source files must have the canonical extensions listed in the 'FileExt'
column below:
@ -90,21 +90,21 @@ FMT CODES:
"""
},
'code': {
'options': lambda cfg,help_notes,proto,s: s.format(
cfg=cfg,
gc=gc,
pnm=gc.proj_name,
pnl=gc.proj_name.lower(),
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
kgs=help_notes('keygen_backends'),
coin_id=help_notes('coin_id'),
dsl=help_notes('dfl_seed_len'),
cu=proto.coin),
'notes': lambda help_notes,s: s.format(
help_notes('fee'),
help_notes('txsign'),
f=help_notes('fmt_codes')),
'options': lambda cfg, help_notes, proto, s: s.format(
cfg = cfg,
gc = gc,
pnm = gc.proj_name,
pnl = gc.proj_name.lower(),
fu = help_notes('rel_fee_desc'),
fl = help_notes('fee_spec_letters'),
kgs = help_notes('keygen_backends'),
coin_id = help_notes('coin_id'),
dsl = help_notes('dfl_seed_len'),
cu = proto.coin),
'notes': lambda help_notes, s: s.format(
e = help_notes('fee'),
s = help_notes('txsign'),
f = help_notes('fmt_codes')),
}
}
@ -116,9 +116,9 @@ if not cfg.autosign:
check_infile(tx_file)
from .tx import CompletedTX, BumpTX, UnsignedTX, OnlineSignedTX
from .tx.sign import txsign,get_seed_files,get_keyaddrlist,get_keylist
from .tx.sign import txsign, get_seed_files, get_keyaddrlist, get_keylist
seed_files = get_seed_files(cfg,cfg._args) if (cfg._args or cfg.send) else None
seed_files = get_seed_files(cfg, cfg._args) if (cfg._args or cfg.send) else None
from .ui import do_license_msg
do_license_msg(cfg)
@ -158,10 +158,10 @@ async def main():
data = orig_tx.__dict__,
automount = cfg.autosign,
check_sent = cfg.autosign or sign_and_send,
twctl = await TwCtl(cfg,orig_tx.proto) if orig_tx.proto.tokensym else None )
twctl = await TwCtl(cfg, orig_tx.proto) if orig_tx.proto.tokensym else None)
from .rpc import rpc_init
tx.rpc = await rpc_init(cfg,tx.proto)
tx.rpc = await rpc_init(cfg, tx.proto)
msg('Creating replacement transaction')
@ -172,9 +172,9 @@ async def main():
if not silent:
msg(f'Minimum fee for new transaction: {tx.min_fee.hl()} {tx.proto.coin}')
tx.usr_fee = tx.get_usr_fee_interactive(fee=cfg.fee,desc='User-selected')
tx.usr_fee = tx.get_usr_fee_interactive(fee=cfg.fee, desc='User-selected')
tx.bump_fee(output_idx,tx.usr_fee)
tx.bump_fee(output_idx, tx.usr_fee)
assert tx.fee <= tx.proto.max_tx_fee
@ -193,10 +193,10 @@ async def main():
msg_r(tx.info.format(terse=True))
if sign_and_send:
tx2 = UnsignedTX(cfg=cfg,data=tx.__dict__)
tx3 = await txsign(cfg,tx2,seed_files,kl,kal)
tx2 = UnsignedTX(cfg=cfg, data=tx.__dict__)
tx3 = await txsign(cfg, tx2, seed_files, kl, kal)
if tx3:
tx4 = await OnlineSignedTX(cfg=cfg,data=tx3.__dict__)
tx4 = await OnlineSignedTX(cfg=cfg, data=tx3.__dict__)
tx4.file.write(ask_write=False)
if await tx4.send():
tx4.file.write(ask_write=False)

View file

@ -21,8 +21,8 @@ mmgen-txcreate: Create a cryptocoin transaction with MMGen- and/or non-MMGen
inputs and outputs
"""
from .cfg import gc,Config
from .util import fmt_list,async_run
from .cfg import gc, Config
from .util import fmt_list, async_run
opts_data = {
'sets': [('yes', True, 'quiet', True)],
@ -68,17 +68,17 @@ opts_data = {
'notes': '\n{c}\n{F}\n{x}',
},
'code': {
'options': lambda cfg,proto,help_notes,s: s.format(
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
fe_all=fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices,fmt='no_spc'),
fe_dfl=cfg._autoset_opts['fee_estimate_mode'].choices[0],
cu=proto.coin,
cfg=cfg),
'notes': lambda cfg,help_notes,s: s.format(
c = help_notes('txcreate'),
F = help_notes('fee'),
x = help_notes('txcreate_examples') )
'options': lambda cfg, proto, help_notes, s: s.format(
fu = help_notes('rel_fee_desc'),
fl = help_notes('fee_spec_letters'),
fe_all = fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices, fmt='no_spc'),
fe_dfl = cfg._autoset_opts['fee_estimate_mode'].choices[0],
cu = proto.coin,
cfg = cfg),
'notes': lambda cfg, help_notes, s: s.format(
c = help_notes('txcreate'),
F = help_notes('fee'),
x = help_notes('txcreate_examples'))
}
}
@ -93,7 +93,7 @@ async def main():
Signable.automount_transaction(asi).check_create_ok()
from .tx import NewTX
tx1 = await NewTX(cfg=cfg,proto=cfg._proto)
tx1 = await NewTX(cfg=cfg, proto=cfg._proto)
from .rpc import rpc_init
tx1.rpc = await rpc_init(cfg)
@ -101,7 +101,7 @@ async def main():
tx2 = await tx1.create(
cmd_args = cfg._args,
locktime = int(cfg.locktime or 0),
do_info = cfg.info )
do_info = cfg.info)
tx2.file.write(
outdir = asi.txauto_dir if cfg.autosign else None,

View file

@ -20,8 +20,8 @@
mmgen-txdo: Create, sign and broadcast an online MMGen transaction
"""
from .cfg import gc,Config
from .util import die,fmt_list,async_run
from .cfg import gc, Config
from .util import die, fmt_list, async_run
from .subseed import SubSeedIdxRange
opts_data = {
@ -102,37 +102,40 @@ FMT CODES:
{x}"""
},
'code': {
'options': lambda cfg,proto,help_notes,s: s.format(
gc=gc,cfg=cfg,pnm=gc.proj_name,pnl=gc.proj_name.lower(),
kgs=help_notes('keygen_backends'),
coin_id=help_notes('coin_id'),
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
ss=help_notes('dfl_subseeds'),
ss_max=SubSeedIdxRange.max_idx,
fe_all=fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices,fmt='no_spc'),
fe_dfl=cfg._autoset_opts['fee_estimate_mode'].choices[0],
dsl=help_notes('dfl_seed_len'),
cu=proto.coin),
'notes': lambda cfg,help_notes,s: s.format(
c = help_notes('txcreate'),
F = help_notes('fee'),
s = help_notes('txsign'),
f = help_notes('fmt_codes'),
x = help_notes('txcreate_examples') ),
'options': lambda cfg, proto, help_notes, s: s.format(
gc = gc,
cfg = cfg,
pnm = gc.proj_name,
pnl = gc.proj_name.lower(),
kgs = help_notes('keygen_backends'),
coin_id = help_notes('coin_id'),
fu = help_notes('rel_fee_desc'),
fl = help_notes('fee_spec_letters'),
ss = help_notes('dfl_subseeds'),
ss_max = SubSeedIdxRange.max_idx,
fe_all = fmt_list(cfg._autoset_opts['fee_estimate_mode'].choices, fmt='no_spc'),
fe_dfl = cfg._autoset_opts['fee_estimate_mode'].choices[0],
dsl = help_notes('dfl_seed_len'),
cu = proto.coin),
'notes': lambda cfg, help_notes, s: s.format(
c = help_notes('txcreate'),
F = help_notes('fee'),
s = help_notes('txsign'),
f = help_notes('fmt_codes'),
x = help_notes('txcreate_examples')),
}
}
cfg = Config(opts_data=opts_data)
from .tx import NewTX, SentTX
from .tx.sign import txsign,get_seed_files,get_keyaddrlist,get_keylist
from .tx.sign import txsign, get_seed_files, get_keyaddrlist, get_keylist
seed_files = get_seed_files(cfg,cfg._args)
seed_files = get_seed_files(cfg, cfg._args)
async def main():
tx1 = await NewTX(cfg=cfg,proto=cfg._proto)
tx1 = await NewTX(cfg=cfg, proto=cfg._proto)
from .rpc import rpc_init
tx1.rpc = await rpc_init(cfg)
@ -140,20 +143,20 @@ async def main():
tx2 = await tx1.create(
cmd_args = cfg._args,
locktime = int(cfg.locktime or 0),
caller = 'txdo' )
caller = 'txdo')
kal = get_keyaddrlist(cfg,cfg._proto)
kal = get_keyaddrlist(cfg, cfg._proto)
kl = get_keylist(cfg)
tx3 = await txsign(cfg,tx2,seed_files,kl,kal)
tx3 = await txsign(cfg, tx2, seed_files, kl, kal)
if tx3:
tx3.file.write(ask_write=False)
tx4 = await SentTX(cfg=cfg, data=tx3.__dict__)
if await tx4.send():
tx4.file.write(ask_overwrite=False,ask_write=False)
tx4.file.write(ask_overwrite=False, ask_write=False)
tx4.print_contract_addr()
else:
die(2,'Transaction could not be signed')
die(2, 'Transaction could not be signed')
async_run(main())

View file

@ -22,7 +22,7 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
import sys
from .cfg import gc,Config
from .cfg import gc, Config
from .util import async_run, die
opts_data = {
@ -98,7 +98,7 @@ async def main():
quiet_open = True)
from .rpc import rpc_init
tx.rpc = await rpc_init(cfg,tx.proto)
tx.rpc = await rpc_init(cfg, tx.proto)
cfg._util.vmsg(f'Getting {tx.desc}{tx.infile}')

View file

@ -20,8 +20,8 @@
mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate'
"""
from .cfg import gc,Config
from .util import msg,ymsg,suf,die,async_run
from .cfg import gc, Config
from .util import msg, ymsg, suf, die, async_run
from .subseed import SubSeedIdxRange
from .color import orange
@ -70,7 +70,7 @@ opts_data = {
-y, --yes Answer 'yes' to prompts, suppress non-essential output
""",
'notes': """
{}
{t}
Seed source files must have the canonical extensions listed in the 'FileExt'
column below:
@ -80,20 +80,20 @@ FMT CODES:
"""
},
'code': {
'options': lambda cfg,proto,help_notes,s: s.format(
cfg=cfg,
gc=gc,
pnm=gc.proj_name,
pnl=gc.proj_name.lower(),
kgs=help_notes('keygen_backends'),
coin_id=help_notes('coin_id'),
dsl=help_notes('dfl_seed_len'),
ss=help_notes('dfl_subseeds'),
ss_max=SubSeedIdxRange.max_idx,
cu=proto.coin),
'notes': lambda help_notes,s: s.format(
help_notes('txsign'),
f=help_notes('fmt_codes')),
'options': lambda cfg, proto, help_notes, s: s.format(
cfg = cfg,
gc = gc,
pnm = gc.proj_name,
pnl = gc.proj_name.lower(),
kgs = help_notes('keygen_backends'),
coin_id = help_notes('coin_id'),
dsl = help_notes('dfl_seed_len'),
ss = help_notes('dfl_subseeds'),
ss_max = SubSeedIdxRange.max_idx,
cu = proto.coin),
'notes': lambda help_notes, s: s.format(
t = help_notes('txsign'),
f = help_notes('fmt_codes')),
}
}
@ -110,9 +110,9 @@ for i in infiles:
if not cfg.info and not cfg.terse_info:
from .ui import do_license_msg
do_license_msg(cfg,immed=True)
do_license_msg(cfg, immed=True)
from .tx.sign import txsign,get_tx_files,get_seed_files,get_keylist,get_keyaddrlist
from .tx.sign import txsign, get_tx_files, get_seed_files, get_keylist, get_keyaddrlist
tx_files = get_tx_files(cfg, infiles)
seed_files = get_seed_files(cfg, infiles)
@ -122,45 +122,45 @@ async def main():
bad_tx_count = 0
tx_num_disp = ''
for tx_num,tx_file in enumerate(tx_files,1):
for tx_num, tx_file in enumerate(tx_files, 1):
if len(tx_files) > 1:
tx_num_disp = f' #{tx_num}'
msg(orange(f'\nTransaction{tx_num_disp} of {len(tx_files)}:'))
from .tx import UnsignedTX
tx1 = UnsignedTX(cfg=cfg,filename=tx_file)
tx1 = UnsignedTX(cfg=cfg, filename=tx_file)
cfg._util.vmsg(f'Successfully opened transaction file {tx_file!r}')
if tx1.proto.sign_mode == 'daemon':
from .rpc import rpc_init
tx1.rpc = await rpc_init( cfg, tx1.proto, ignore_wallet=True )
tx1.rpc = await rpc_init(cfg, tx1.proto, ignore_wallet=True)
if cfg.tx_id:
msg(tx1.txid)
continue
if cfg.info or cfg.terse_info:
tx1.view(pause=False,terse=cfg.terse_info)
tx1.view(pause=False, terse=cfg.terse_info)
continue
if not cfg.yes:
tx1.info.view_with_prompt(f'View data for transaction{tx_num_disp}?')
kal = get_keyaddrlist(cfg,tx1.proto)
kal = get_keyaddrlist(cfg, tx1.proto)
kl = get_keylist(cfg)
tx2 = await txsign(cfg,tx1,seed_files,kl,kal,tx_num_disp)
tx2 = await txsign(cfg, tx1, seed_files, kl, kal, tx_num_disp)
if tx2:
if not cfg.yes:
tx2.add_comment() # edits an existing comment
tx2.file.write(ask_write=not cfg.yes,ask_write_default_yes=True,add_desc=tx_num_disp)
tx2.file.write(ask_write=not cfg.yes, ask_write_default_yes=True, add_desc=tx_num_disp)
else:
ymsg('Transaction could not be signed')
bad_tx_count += 1
if bad_tx_count:
die(2,f'{bad_tx_count} transaction{suf(bad_tx_count)} could not be signed')
die(2, f'{bad_tx_count} transaction{suf(bad_tx_count)} could not be signed')
async_run(main())

View file

@ -20,11 +20,11 @@
main_wallet: Entry point for MMGen wallet-related scripts
"""
import sys,os
from .cfg import gc,Config
from .color import green,yellow
from .util import msg,gmsg_r,ymsg,bmsg,die,capfirst
from .wallet import Wallet,get_wallet_cls
import sys, os
from .cfg import gc, Config
from .color import green, yellow
from .util import msg, gmsg_r, ymsg, bmsg, die, capfirst
from .wallet import Wallet, get_wallet_cls
usage = '[opts] [infile]'
nargs = 1
@ -126,26 +126,26 @@ FMT CODES:
"""
},
'code': {
'options': lambda cfg,help_notes,s: s.format(
iaction=capfirst(iaction),
oaction=capfirst(oaction),
ms_min=help_notes('MasterShareIdx').min_val,
ms_max=help_notes('MasterShareIdx').max_val,
dsl=help_notes('dfl_seed_len'),
cfg=cfg,
gc=gc,
'options': lambda cfg, help_notes, s: s.format(
iaction = capfirst(iaction),
oaction = capfirst(oaction),
ms_min = help_notes('MasterShareIdx').min_val,
ms_max = help_notes('MasterShareIdx').max_val,
dsl = help_notes('dfl_seed_len'),
cfg = cfg,
gc = gc,
),
'notes': lambda cfg,help_mod,help_notes,s: s.format(
f=help_notes('fmt_codes'),
n_ss=('',help_mod('seedsplit')+'\n\n')[do_ss_note],
n_sw=('',help_notes('subwallet')+'\n\n')[do_sw_note],
n_pw=help_notes('passwd'),
n_bw=('','\n\n'+help_notes('brainwallet'))[do_bw_note]
'notes': lambda cfg, help_mod, help_notes, s: s.format(
f = help_notes('fmt_codes'),
n_ss = ('', help_mod('seedsplit')+'\n\n')[do_ss_note],
n_sw = ('', help_notes('subwallet')+'\n\n')[do_sw_note],
n_pw = help_notes('passwd'),
n_bw = ('', '\n\n'+help_notes('brainwallet'))[do_bw_note]
)
}
}
cfg = Config( opts_data=opts_data, opt_filter=opt_filter, need_proto=False )
cfg = Config(opts_data=opts_data, opt_filter=opt_filter, need_proto=False)
cmd_args = cfg._args
@ -154,17 +154,17 @@ if invoked_as == 'subgen':
ss_idx = SubSeedIdx(cmd_args.pop())
elif invoked_as == 'seedsplit':
from .obj import get_obj
from .seedsplit import SeedSplitSpecifier,MasterShareIdx
from .seedsplit import SeedSplitSpecifier, MasterShareIdx
master_share = MasterShareIdx(cfg.master_share) if cfg.master_share else None
if cmd_args:
sss = get_obj(SeedSplitSpecifier,s=cmd_args.pop(),silent=True)
sss = get_obj(SeedSplitSpecifier, s=cmd_args.pop(), silent=True)
if master_share:
if not sss:
sss = SeedSplitSpecifier('1:2')
elif sss.idx == 1:
m1 = 'Share index of 1 meaningless in master share context.'
m2 = 'To generate a master share, omit the seed split specifier.'
die(1,m1+' '+m2)
die(1, m1+' '+m2)
elif not sss:
cfg._usage()
elif master_share:
@ -172,14 +172,14 @@ elif invoked_as == 'seedsplit':
else:
cfg._usage()
from .fileutil import check_infile,get_seed_file
from .fileutil import check_infile, get_seed_file
if cmd_args:
if invoked_as == 'gen' or len(cmd_args) > 1:
cfg._usage()
check_infile(cmd_args[0])
sf = get_seed_file(cfg,nargs,invoked_as=invoked_as)
sf = get_seed_file(cfg, nargs, invoked_as=invoked_as)
if invoked_as != 'chk':
from .ui import do_license_msg
@ -192,37 +192,37 @@ else:
cfg = cfg,
fn = sf,
passchg = invoked_as == 'passchg',
passwd_file = False if cfg.passwd_file_new_only else None )
passwd_file = False if cfg.passwd_file_new_only else None)
m1 = green('Processing input wallet ')
m2 = ss_in.seed.sid.hl()
m3 = yellow(' (default wallet)') if sf and os.path.dirname(sf) == cfg.data_dir else ''
msg(m1+m2+m3)
if invoked_as == 'chk':
lbl = ss_in.ssdata.label.hl() if hasattr(ss_in.ssdata,'label') else 'NONE'
lbl = ss_in.ssdata.label.hl() if hasattr(ss_in.ssdata, 'label') else 'NONE'
cfg._util.vmsg(f'Wallet label: {lbl}')
# TODO: display creation date
sys.exit(0)
if invoked_as != 'gen':
gmsg_r('Processing output wallet' + ('\n',' ')[invoked_as == 'seedsplit'])
gmsg_r('Processing output wallet' + ('\n', ' ')[invoked_as == 'seedsplit'])
if invoked_as == 'subgen':
ss_out = Wallet(
cfg = cfg,
seed_bin = ss_in.seed.subseed(ss_idx,print_msg=True).data )
seed_bin = ss_in.seed.subseed(ss_idx, print_msg=True).data)
elif invoked_as == 'seedsplit':
shares = ss_in.seed.split(sss.count,sss.id,master_share)
seed_out = shares.get_share_by_idx(sss.idx,base_seed=True)
shares = ss_in.seed.split(sss.count, sss.id, master_share)
seed_out = shares.get_share_by_idx(sss.idx, base_seed=True)
msg(seed_out.get_desc(ui=True))
ss_out = Wallet(
cfg = cfg,
seed = seed_out )
seed = seed_out)
else:
ss_out = Wallet(
cfg = cfg,
ss = ss_in,
passchg = invoked_as == 'passchg' )
passchg = invoked_as == 'passchg')
if invoked_as == 'gen':
cfg._util.qmsg(f"This wallet's Seed ID: {ss_out.seed.sid.hl()}")
@ -230,18 +230,18 @@ if invoked_as == 'gen':
if invoked_as == 'passchg':
def data_changed(attrs):
for attr in attrs:
if getattr(ss_out.ssdata,attr) != getattr(ss_in.ssdata,attr):
if getattr(ss_out.ssdata, attr) != getattr(ss_in.ssdata, attr):
return True
return False
if not ( cfg.force_update or data_changed(('passwd','hash_preset','label')) ):
die(1,'Password, hash preset and label are unchanged. Taking no action')
if not (cfg.force_update or data_changed(('passwd', 'hash_preset', 'label'))):
die(1, 'Password, hash preset and label are unchanged. Taking no action')
if invoked_as == 'passchg':
def secure_delete(fn):
bmsg('Securely deleting old wallet')
from .fileutil import shred_file
shred_file( fn, verbose = cfg.verbose )
shred_file(fn, verbose = cfg.verbose)
def rename_old_wallet_maybe(silent):
# though very unlikely, old and new wallets could have same Key ID and thus same filename.
@ -251,8 +251,8 @@ if invoked_as == 'passchg':
if not silent:
ymsg(
'Warning: diverting old wallet {old_fn!r} due to Key ID collision. ' +
'Please securely delete or move the diverted file!' )
os.rename( old_fn, old_fn+'.divert' )
'Please securely delete or move the diverted file!')
os.rename(old_fn, old_fn+'.divert')
return old_fn+'.divert'
else:
return old_fn
@ -263,26 +263,26 @@ if invoked_as == 'passchg':
cfg = cfg,
message = yellow('Confirmation of default wallet update'),
action = 'update the default wallet',
exit_msg = 'Password not changed' )
exit_msg = 'Password not changed')
old_wallet = rename_old_wallet_maybe(silent=True)
ss_out.write_to_file( desc='New wallet', outdir=cfg.data_dir )
secure_delete( old_wallet )
ss_out.write_to_file(desc='New wallet', outdir=cfg.data_dir)
secure_delete(old_wallet)
else:
old_wallet = rename_old_wallet_maybe(silent=False)
ss_out.write_to_file()
from .ui import keypress_confirm
if keypress_confirm( cfg, f'Securely delete old wallet {old_wallet!r}?' ):
secure_delete( old_wallet )
if keypress_confirm(cfg, f'Securely delete old wallet {old_wallet!r}?'):
secure_delete(old_wallet)
elif invoked_as == 'gen' and not cfg.outdir and not cfg.stdout:
from .filename import find_file_in_dir
if find_file_in_dir( get_wallet_cls('mmgen'), cfg.data_dir ):
if find_file_in_dir(get_wallet_cls('mmgen'), cfg.data_dir):
ss_out.write_to_file()
else:
from .ui import keypress_confirm
if keypress_confirm(
cfg,
'Make this wallet your default and move it to the data directory?',
default_yes = True ):
default_yes = True):
ss_out.write_to_file(outdir=cfg.data_dir)
else:
ss_out.write_to_file()

View file

@ -89,11 +89,11 @@ opts_data = {
},
'code': {
'options': lambda cfg, s: s.format(
D=xmrwallet.uarg_info['daemon'].annot,
R=xmrwallet.uarg_info['tx_relay_daemon'].annot,
cfg=cfg,
gc=gc,
tp=fmt_dict(xmrwallet.tx_priorities, fmt='equal_compact')
D = xmrwallet.uarg_info['daemon'].annot,
R = xmrwallet.uarg_info['tx_relay_daemon'].annot,
cfg = cfg,
gc = gc,
tp = fmt_dict(xmrwallet.tx_priorities, fmt='equal_compact')
),
'notes': lambda help_mod, s: s.format(
xmrwallet_help = help_mod('xmrwallet')