handle MMGen exceptions via die()
- exception module is imported only after an error occurs
This commit is contained in:
parent
41376eb515
commit
aad252a077
50 changed files with 143 additions and 169 deletions
|
|
@ -17,7 +17,7 @@ from collections import namedtuple
|
|||
import mmgen.tx.base as TxBase
|
||||
from ....opts import opt
|
||||
from ....obj import MMGenObject,MMGenList,HexStr
|
||||
from ....util import msg,dmsg,make_chksum_6
|
||||
from ....util import msg,dmsg,make_chksum_6,die
|
||||
|
||||
def addr2pubhash(proto,addr):
|
||||
ap = proto.parse_addr(addr)
|
||||
|
|
@ -100,7 +100,7 @@ def DeserializeTX(proto,txhex):
|
|||
if has_witness:
|
||||
u = bshift(2,skip=True).hex()
|
||||
if u != '0001':
|
||||
raise IllegalWitnessFlagValue(f'{u!r}: Illegal value for flag in transaction!')
|
||||
die( 'IllegalWitnessFlagValue', f'{u!r}: Illegal value for flag in transaction!' )
|
||||
|
||||
d['num_txins'] = readVInt()
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ def DeserializeTX(proto,txhex):
|
|||
d['witness_size'] = 0
|
||||
|
||||
if len(tx) - var.idx != 4:
|
||||
raise TxHexParseError('TX hex has invalid length: {} extra bytes'.format(len(tx)-var.idx-4))
|
||||
die( 'TxHexParseError', 'TX hex has invalid length: {} extra bytes'.format(len(tx)-var.idx-4) )
|
||||
|
||||
d['locktime'] = bytes2int(bshift(4))
|
||||
d['unsigned_hex'] = var.raw_tx.hex()
|
||||
|
|
@ -283,8 +283,7 @@ class Base(TxBase.Base):
|
|||
"""
|
||||
|
||||
def do_error(errmsg):
|
||||
from ....exception import TxHexMismatch
|
||||
raise TxHexMismatch(errmsg+'\n'+hdr)
|
||||
die( 'TxHexMismatch', errmsg+'\n'+hdr )
|
||||
|
||||
def check_equal(desc,hexio,mmio):
|
||||
if mmio != hexio:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import mmgen.tx.new as TxBase
|
|||
from .base import Base
|
||||
from ....opts import opt
|
||||
from ....obj import HexStr,MMGenTxID
|
||||
from ....util import dmsg,vmsg,make_chksum_6
|
||||
from ....util import dmsg,vmsg,make_chksum_6,die
|
||||
|
||||
class New(Base,TxBase.New):
|
||||
usr_fee_prompt = 'Enter transaction fee: '
|
||||
|
|
@ -98,7 +98,7 @@ class New(Base,TxBase.New):
|
|||
fee = self.sum_inputs() - self.sum_outputs()
|
||||
if fee > self.proto.max_tx_fee:
|
||||
c = self.proto.coin
|
||||
raise MaxFeeExceeded(f'Transaction fee of {fee} {c} too high! (> {self.proto.max_tx_fee} {c})')
|
||||
die( 'MaxFeeExceeded', f'Transaction fee of {fee} {c} too high! (> {self.proto.max_tx_fee} {c})' )
|
||||
|
||||
def final_inputs_ok_msg(self,funds_left):
|
||||
return 'Transaction produces {} {} in change'.format(
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ base_proto.bitcoin.tx.signed: Bitcoin signed transaction class
|
|||
|
||||
import mmgen.tx.signed as TxBase
|
||||
from .completed import Completed
|
||||
from ....util import fmt,vmsg
|
||||
from ....util import fmt,vmsg,die
|
||||
|
||||
class Signed(Completed,TxBase.Signed):
|
||||
|
||||
|
|
@ -25,8 +25,7 @@ class Signed(Completed,TxBase.Signed):
|
|||
vmsg(f'\nVsize: {vsize} (true) {est_vsize} (estimated)')
|
||||
ratio = float(est_vsize) / vsize
|
||||
if not (0.95 < ratio < 1.05): # allow for 5% error
|
||||
from ....exception import BadTxSizeEstimate
|
||||
raise BadTxSizeEstimate(fmt(f"""
|
||||
die( 'BadTxSizeEstimate', fmt(f"""
|
||||
Estimated transaction vsize is {ratio:1.2f} times the true vsize
|
||||
Your transaction fee estimates will be inaccurate
|
||||
Please re-create and re-sign the transaction using the option --vsize-adj={1/ratio:1.2f}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class Unsigned(Completed,TxBase.Unsigned):
|
|||
new.compare_size_and_estimated_size(tx_decoded)
|
||||
new.coin_txid = CoinTxID(self.deserialized.txid)
|
||||
if not new.coin_txid == tx_decoded['txid']:
|
||||
raise BadMMGenTxID('txid mismatch (after signing)')
|
||||
die( 'BadMMGenTxID', 'txid mismatch (after signing)' )
|
||||
msg('OK')
|
||||
return new
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -174,5 +174,5 @@ class TokenResolve(TokenCommon,metaclass=AsyncInit):
|
|||
self.addr = TokenAddr(proto,addr)
|
||||
decimals = await self.get_decimals() # requires self.addr!
|
||||
if not decimals:
|
||||
raise TokenNotInBlockchain(f'Token {addr!r} not in blockchain')
|
||||
die( 'TokenNotInBlockchain', f'Token {addr!r} not in blockchain' )
|
||||
Token.__init__(self,proto,addr,decimals,rpc)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
altcoins.base_proto.ethereum.twctl: Ethereum tracking wallet control class
|
||||
"""
|
||||
|
||||
from ...util import msg,ymsg,write_mode
|
||||
from ...util import msg,ymsg,write_mode,die
|
||||
from ...twctl import TrackingWallet
|
||||
from ...addr import is_coin_addr,is_mmgen_id
|
||||
from ...amt import ETHAmt
|
||||
|
|
@ -160,13 +160,12 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet):
|
|||
|
||||
if self.importing and token_addr:
|
||||
if not is_coin_addr(proto,token_addr):
|
||||
raise InvalidTokenAddress(f'{token_addr!r}: invalid token address')
|
||||
die( 'InvalidTokenAddress', f'{token_addr!r}: invalid token address' )
|
||||
else:
|
||||
assert token_addr == None,'EthereumTokenTrackingWallet_chk1'
|
||||
token_addr = await self.sym2addr(proto.tokensym) # returns None on failure
|
||||
if not is_coin_addr(proto,token_addr):
|
||||
from ...exception import UnrecognizedTokenSymbol
|
||||
raise UnrecognizedTokenSymbol(f'Specified token {proto.tokensym!r} could not be resolved!')
|
||||
die( 'UnrecognizedTokenSymbol', f'Specified token {proto.tokensym!r} could not be resolved!' )
|
||||
|
||||
from ...addr import TokenAddr
|
||||
self.token = TokenAddr(proto,token_addr)
|
||||
|
|
@ -175,7 +174,7 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet):
|
|||
if self.importing:
|
||||
await self.import_token(self.token)
|
||||
else:
|
||||
raise TokenNotInWallet(f'Specified token {self.token!r} not in wallet!')
|
||||
die( 'TokenNotInWallet', f'Specified token {self.token!r} not in wallet!' )
|
||||
|
||||
self.decimals = self.get_param('decimals')
|
||||
self.symbol = self.get_param('symbol')
|
||||
|
|
|
|||
|
|
@ -139,10 +139,10 @@ class New(Base,TxBase.New):
|
|||
ret.append(waddr)
|
||||
break
|
||||
else:
|
||||
raise UserAddressNotInWallet(errmsg.format(addr))
|
||||
die( 'UserAddressNotInWallet', errmsg.format(addr) )
|
||||
elif is_coin_addr(self.proto,addr):
|
||||
if not addr in data_root:
|
||||
raise UserAddressNotInWallet(errmsg.format(addr))
|
||||
die( 'UserAddressNotInWallet', errmsg.format(addr) )
|
||||
ret.append(addr)
|
||||
else:
|
||||
die(1,f'{addr!r}: not an MMGen ID or coin address')
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ baseconv.py: base conversion class for the MMGen suite
|
|||
|
||||
from collections import namedtuple
|
||||
|
||||
from .exception import BaseConversionError,BaseConversionPadError,HexadecimalStringError,SeedLengthError
|
||||
from .util import die
|
||||
|
||||
def is_b58_str(s):
|
||||
|
|
@ -123,7 +122,7 @@ class baseconv(object):
|
|||
elif pad == 'seed':
|
||||
return seed_pad_func()
|
||||
else:
|
||||
raise BaseConversionPadError(f"{pad!r}: illegal value for 'pad' (must be None,'seed' or int)")
|
||||
die('BaseConversionPadError',f"{pad!r}: illegal value for 'pad' (must be None,'seed' or int)")
|
||||
|
||||
def tohex(self,words_arg,pad=None):
|
||||
"convert string or list data of instance base to hex string"
|
||||
|
|
@ -136,13 +135,13 @@ class baseconv(object):
|
|||
desc = self.desc.short
|
||||
|
||||
if len(words) == 0:
|
||||
raise BaseConversionError(f'empty {desc} data')
|
||||
die('BaseConversionError',f'empty {desc} data')
|
||||
|
||||
def get_seed_pad():
|
||||
assert hasattr(self,'seedlen_map_rev'), f'seed padding not supported for base {self.wl_id!r}'
|
||||
d = self.seedlen_map_rev
|
||||
if not len(words) in d:
|
||||
raise BaseConversionError(
|
||||
die( 'BaseConversionError',
|
||||
f'{len(words)}: invalid length for seed-padded {desc} data in base conversion' )
|
||||
return d[len(words)]
|
||||
|
||||
|
|
@ -151,7 +150,7 @@ class baseconv(object):
|
|||
base = len(wl)
|
||||
|
||||
if not set(words) <= set(wl):
|
||||
raise BaseConversionError(
|
||||
die( 'BaseConversionError',
|
||||
( 'seed data' if pad == 'seed' else f'{words_arg!r}:' ) +
|
||||
f' not in {desc} format' )
|
||||
|
||||
|
|
@ -164,7 +163,7 @@ class baseconv(object):
|
|||
|
||||
from .util import is_hex_str
|
||||
if not is_hex_str(hexstr):
|
||||
raise HexadecimalStringError(
|
||||
die( 'HexadecimalStringError',
|
||||
( 'seed data' if pad == 'seed' else f'{hexstr!r}:' ) +
|
||||
' not a hexadecimal string' )
|
||||
|
||||
|
|
@ -174,13 +173,13 @@ class baseconv(object):
|
|||
"convert byte string to list or string data of instance base"
|
||||
|
||||
if not bytestr:
|
||||
raise BaseConversionError('empty data not allowed in base conversion')
|
||||
die( 'BaseConversionError', 'empty data not allowed in base conversion' )
|
||||
|
||||
def get_seed_pad():
|
||||
assert hasattr(self,'seedlen_map'), f'seed padding not supported for base {self.wl_id!r}'
|
||||
d = self.seedlen_map
|
||||
if not len(bytestr) in d:
|
||||
raise SeedLengthError(
|
||||
die( 'SeedLengthError',
|
||||
f'{len(bytestr)}: invalid byte length for seed data in seed-padded base conversion' )
|
||||
return d[len(bytestr)]
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,8 @@ bip39.py - Data and routines for BIP39 mnemonic seed phrases
|
|||
|
||||
from hashlib import sha256
|
||||
|
||||
from .exception import MnemonicError
|
||||
from .baseconv import baseconv
|
||||
from .util import is_hex_str
|
||||
from .util import is_hex_str,die
|
||||
|
||||
def is_bip39_str(s):
|
||||
return bool( bip39().tohex(s.split()) )
|
||||
|
|
@ -59,7 +58,7 @@ class bip39(baseconv):
|
|||
for k,v in cls.constants.items():
|
||||
if v.mn_len == nwords:
|
||||
return k//8 if in_bytes else k//4 if in_hex else k
|
||||
raise MnemonicError(f'{nwords!r}: invalid word length for BIP39 mnemonic')
|
||||
die( 'MnemonicError', f'{nwords!r}: invalid word length for BIP39 mnemonic' )
|
||||
|
||||
@classmethod
|
||||
def seedlen2nwords(cls,seed_len,in_bytes=False,in_hex=False):
|
||||
|
|
@ -83,7 +82,7 @@ class bip39(baseconv):
|
|||
|
||||
for n,w in enumerate(words):
|
||||
if w not in wl:
|
||||
raise MnemonicError(f'word #{n+1} is not in the BIP39 word list')
|
||||
die( 'MnemonicError', f'word #{n+1} is not in the BIP39 word list' )
|
||||
|
||||
res = ''.join(['{:011b}'.format(wl.index(w)) for w in words])
|
||||
|
||||
|
|
@ -92,7 +91,7 @@ class bip39(baseconv):
|
|||
bitlen = k
|
||||
break
|
||||
else:
|
||||
raise MnemonicError(f'{len(words)}: invalid BIP39 seed phrase length')
|
||||
die( 'MnemonicError', f'{len(words)}: invalid BIP39 seed phrase length' )
|
||||
|
||||
seed_bin = res[:bitlen]
|
||||
chk_bin = res[bitlen:]
|
||||
|
|
@ -105,7 +104,7 @@ class bip39(baseconv):
|
|||
chk_bin_chk = '{:0{w}b}'.format(int(chk_hex_chk,16),w=256)[:chk_len]
|
||||
|
||||
if chk_bin != chk_bin_chk:
|
||||
raise MnemonicError('invalid BIP39 seed phrase checksum')
|
||||
die( 'MnemonicError', 'invalid BIP39 seed phrase checksum' )
|
||||
|
||||
return seed_hex
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import sys,os,re
|
|||
from collections import namedtuple
|
||||
|
||||
from .globalvars import *
|
||||
from .exception import CfgFileParseError
|
||||
from .util import *
|
||||
|
||||
def cfg_file(id_str):
|
||||
|
|
@ -92,7 +91,7 @@ class CfgFile(object):
|
|||
if m:
|
||||
yield self.line_data(m[1],m[3],lineno,None)
|
||||
else:
|
||||
raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}')
|
||||
die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' )
|
||||
return gen_lines()
|
||||
|
||||
@classmethod
|
||||
|
|
@ -135,7 +134,7 @@ class CfgFileSample(CfgFile):
|
|||
if m:
|
||||
return self.line_data(m[2],m[4],lineno,chunk)
|
||||
else:
|
||||
raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}')
|
||||
die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' )
|
||||
|
||||
def gen_chunks(lines):
|
||||
hdr = True
|
||||
|
|
@ -163,7 +162,7 @@ class CfgFileSample(CfgFile):
|
|||
chunk.append(line)
|
||||
last_nonblank = lineno
|
||||
else:
|
||||
raise CfgFileParseError(f'Parse error in file {self.fn!r}, line {lineno}')
|
||||
die( 'CfgFileParseError', f'Parse error in file {self.fn!r}, line {lineno}' )
|
||||
|
||||
if chunk:
|
||||
yield process_chunk(chunk,last_nonblank)
|
||||
|
|
|
|||
|
|
@ -80,8 +80,7 @@ class Daemon(Lockable):
|
|||
try:
|
||||
cp = run(cmd,check=False,stdout=out,stderr=out)
|
||||
except Exception as e:
|
||||
from .exception import MMGenCalledProcessError
|
||||
raise MMGenCalledProcessError(f'Error starting executable: {type(e).__name__} [Errno {e.errno}]')
|
||||
die( 'MMGenCalledProcessError', f'Error starting executable: {type(e).__name__} [Errno {e.errno}]' )
|
||||
if self.debug:
|
||||
print(cp)
|
||||
return cp
|
||||
|
|
|
|||
|
|
@ -54,16 +54,14 @@ class Filename(MMGenObject):
|
|||
if base_class:
|
||||
subclass = base_class.ext_to_type(self.ext,proto)
|
||||
if not subclass:
|
||||
from .exception import BadFileExtension
|
||||
raise BadFileExtension(f'{self.ext!r}: not a recognized file extension for {base_class}')
|
||||
die( 'BadFileExtension', f'{self.ext!r}: not a recognized file extension for {base_class}' )
|
||||
|
||||
self.subclass = subclass
|
||||
|
||||
try:
|
||||
st = os.stat(fn)
|
||||
except:
|
||||
from .exception import FileNotFound
|
||||
raise FileNotFound(f'{fn!r}: file not found')
|
||||
die( 'FileNotFound', f'{fn!r}: file not found' )
|
||||
|
||||
import stat
|
||||
if stat.S_ISBLK(st.st_mode):
|
||||
|
|
|
|||
|
|
@ -89,8 +89,7 @@ def _check_file_type_and_access(fname,ftype,blkdev_ok=False):
|
|||
try:
|
||||
mode = os.stat(fname).st_mode
|
||||
except:
|
||||
from .exception import FileNotFound
|
||||
raise FileNotFound(f'Requested {ftype} {fname!r} not found')
|
||||
die( 'FileNotFound', f'Requested {ftype} {fname!r} not found' )
|
||||
|
||||
for t in ok_types:
|
||||
if t[0](mode):
|
||||
|
|
@ -289,8 +288,8 @@ def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False,q
|
|||
data = data.decode()
|
||||
|
||||
if len(data) == g.max_input_size + 1:
|
||||
from .exception import MaxInputSizeExceeded
|
||||
raise MaxInputSizeExceeded(f'Too much input data! Max input data size: {f.max_input_size} bytes')
|
||||
die( 'MaxInputSizeExceeded',
|
||||
f'Too much input data! Max input data size: {f.max_input_size} bytes' )
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
flags.py: Class flags and opts for the MMGen suite
|
||||
"""
|
||||
|
||||
from .exception import ClassFlagsError
|
||||
from .base_obj import AttrCtrl,Lockable
|
||||
from .util import fmt_list
|
||||
from .util import fmt_list,die
|
||||
|
||||
class ClassFlags(AttrCtrl):
|
||||
_name = 'flags'
|
||||
|
|
@ -35,10 +34,10 @@ class ClassFlags(AttrCtrl):
|
|||
|
||||
for a in self._available:
|
||||
if a.startswith('_'):
|
||||
raise ClassFlagsError(f'{a!r}: {self._desc} cannot begin with an underscore')
|
||||
die( 'ClassFlagsError', f'{a!r}: {self._desc} cannot begin with an underscore' )
|
||||
for b in self.reserved_attrs:
|
||||
if a == b:
|
||||
raise ClassFlagsError(f'{a!r}: {b} is a reserved name for {self._desc}')
|
||||
die( 'ClassFlagsError', f'{a!r}: {b} is a reserved name for {self._desc}' )
|
||||
|
||||
if arg:
|
||||
assert type(arg) in (list,tuple), f"{arg!r}: {self._name!r} must be list or tuple"
|
||||
|
|
@ -69,14 +68,14 @@ class ClassFlags(AttrCtrl):
|
|||
assert type(val) is bool, f'{val!r} not boolean'
|
||||
old_val = getattr(self,name)
|
||||
if val and old_val:
|
||||
raise ClassFlagsError(f'{self._desc} {name!r} already set')
|
||||
die( 'ClassFlagsError', f'{self._desc} {name!r} already set' )
|
||||
if not val and not old_val:
|
||||
raise ClassFlagsError(f'{self._desc} {name!r} not set, so cannot be unset')
|
||||
die( 'ClassFlagsError', f'{self._desc} {name!r} not set, so cannot be unset' )
|
||||
|
||||
super().__setattr__(name,val)
|
||||
|
||||
def not_available_error(self,name):
|
||||
raise ClassFlagsError('{!r}: unrecognized {} for {}: (available {}: {})'.format(
|
||||
die( 'ClassFlagsError', '{!r}: unrecognized {} for {}: (available {}: {})'.format(
|
||||
name,
|
||||
self._desc,
|
||||
type(self._parent).__name__,
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ class PrivKey(bytes,Hilite,InitErrors,MMGenObject):
|
|||
me.wif = str.__new__(WifKey,wif) # check has been done
|
||||
me.orig_bytes = None
|
||||
if k.sec != proto.preprocess_key(k.sec,k.pubkey_type):
|
||||
from .exception import PrivateKeyError
|
||||
raise PrivateKeyError(
|
||||
f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}')
|
||||
from .util import die
|
||||
die( 'PrivateKeyError',
|
||||
f'{proto.cls_name} WIF key {me.wif!r} encodes private key with invalid value {me}' )
|
||||
me.proto = proto
|
||||
return me
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -64,8 +64,9 @@ class keygen_backend:
|
|||
try:
|
||||
from .secp256k1 import priv2pub
|
||||
if not priv2pub(bytes.fromhex('deadbeef'*8),1):
|
||||
from .exception import ExtensionModuleError
|
||||
raise ExtensionModuleError('Unable to execute priv2pub() from secp256k1 extension module')
|
||||
from .util import die
|
||||
die( 'ExtensionModuleError',
|
||||
'Unable to execute priv2pub() from secp256k1 extension module' )
|
||||
return True
|
||||
except Exception as e:
|
||||
if not silent:
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ class LEDControl:
|
|||
except: pass
|
||||
else: break
|
||||
else:
|
||||
from mmgen.exception import NoLEDSupport
|
||||
raise NoLEDSupport('Control files not found! LED control not supported on this system')
|
||||
from .util import die
|
||||
die( 'NoLEDSupport', 'Control files not found! LED control not supported on this system' )
|
||||
|
||||
msg(f'{board.name} board detected')
|
||||
|
||||
|
|
@ -89,6 +89,7 @@ class LEDControl:
|
|||
fp.write(f'{init_val}\n')
|
||||
return True
|
||||
except PermissionError:
|
||||
from .util import die
|
||||
die(2,'\n'+fmt(f"""
|
||||
You do not have access to the {desc} file
|
||||
To allow access, run the following command:
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ def launch(mod):
|
|||
|
||||
_o = namedtuple('exit_data',['color','exit_val','fs'])
|
||||
d = {
|
||||
0: _o(nocolor, 1, '{message}'),
|
||||
1: _o(nocolor, 1, '{message}'),
|
||||
2: _o(yellow, 2, '{message}'),
|
||||
3: _o(yellow, 3, '\nMMGen Error ({name}): {message}'),
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ 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():
|
||||
raise 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:
|
||||
max_dlen_spec = '10kB' # limit input to 10KB for now
|
||||
max_dlen = parse_bytespec(max_dlen_spec)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ obj.py: MMGen native classes
|
|||
import sys,os,re,unicodedata
|
||||
|
||||
from .objmethods import *
|
||||
from .exception import BadTwComment
|
||||
|
||||
def get_obj(objname,*args,**kwargs):
|
||||
"""
|
||||
|
|
@ -378,7 +377,7 @@ class MMGenWalletLabel(MMGenLabel):
|
|||
class TwComment(MMGenLabel):
|
||||
max_screen_width = 80
|
||||
desc = 'tracking wallet comment'
|
||||
exc = BadTwComment
|
||||
exc = 'BadTwComment'
|
||||
|
||||
class MMGenTxLabel(MMGenLabel):
|
||||
max_len = 72
|
||||
|
|
|
|||
|
|
@ -115,13 +115,14 @@ class InitErrors:
|
|||
if m2:
|
||||
errmsg = repr(m2) + '\n' + errmsg
|
||||
|
||||
if hasattr(cls,'passthru_excs') and type(e) in cls.passthru_excs:
|
||||
from .util import die
|
||||
|
||||
if hasattr(cls,'passthru_excs') and type(e).__name__ in cls.passthru_excs:
|
||||
raise
|
||||
elif hasattr(cls,'exc'):
|
||||
raise cls.exc(errmsg)
|
||||
die( cls.exc, errmsg )
|
||||
else:
|
||||
from .exception import ObjectInitError
|
||||
raise ObjectInitError(errmsg)
|
||||
die( 'ObjectInitError', errmsg )
|
||||
|
||||
@classmethod
|
||||
def method_not_implemented(cls):
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ opts.py: MMGen-specific options processing after generic processing by share.Op
|
|||
"""
|
||||
import sys,os,stat
|
||||
|
||||
from .exception import UserOptError,CfgFileParseError
|
||||
from .globalvars import g
|
||||
from .base_obj import Lockable
|
||||
|
||||
|
|
@ -163,11 +162,13 @@ def override_globals_from_cfg_file(ucfg,need_proto):
|
|||
refval = getattr(cls,attr)
|
||||
val = ucfg.parse_value(d.value,refval)
|
||||
if not val:
|
||||
raise CfgFileParseError(f'Parse error in file {ucfg.fn!r}, line {d.lineno}')
|
||||
from .util import die
|
||||
die( 'CfgFileParseError', f'Parse error in file {ucfg.fn!r}, line {d.lineno}' )
|
||||
val_conv = set_for_type(val,refval,attr,src=ucfg.fn)
|
||||
setattr(cls,attr,val_conv)
|
||||
else:
|
||||
raise CfgFileParseError(f'{d.name!r}: unrecognized option in {ucfg.fn!r}, line {d.lineno}')
|
||||
from .util import die
|
||||
die( 'CfgFileParseError', f'{d.name!r}: unrecognized option in {ucfg.fn!r}, line {d.lineno}' )
|
||||
|
||||
def override_globals_and_set_opts_from_env(opt):
|
||||
for name in g.env_opts:
|
||||
|
|
@ -426,39 +427,39 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
try:
|
||||
l = val.split(sep)
|
||||
except:
|
||||
raise UserOptError(f'{val!r}: invalid {desc} (not {sepword}-separated list)')
|
||||
die( 'UserOptError', f'{val!r}: invalid {desc} (not {sepword}-separated list)' )
|
||||
|
||||
if len(l) != n:
|
||||
raise UserOptError(f'{val!r}: invalid {desc} ({n} {sepword}-separated items required)')
|
||||
die( 'UserOptError', f'{val!r}: invalid {desc} ({n} {sepword}-separated items required)' )
|
||||
|
||||
def opt_compares(val,op_str,target,desc,desc2=''):
|
||||
import operator as o
|
||||
op_f = { '<':o.lt, '<=':o.le, '>':o.gt, '>=':o.ge, '=':o.eq }[op_str]
|
||||
if not op_f(val,target):
|
||||
d2 = desc2 + ' ' if desc2 else ''
|
||||
raise UserOptError(f'{val}: invalid {desc} ({d2}not {op_str} {target})')
|
||||
die( 'UserOptError', f'{val}: invalid {desc} ({d2}not {op_str} {target})' )
|
||||
|
||||
def opt_is_int(val,desc):
|
||||
if not is_int(val):
|
||||
raise UserOptError(f'{val!r}: invalid {desc} (not an integer)')
|
||||
die( 'UserOptError', f'{val!r}: invalid {desc} (not an integer)' )
|
||||
|
||||
def opt_is_float(val,desc):
|
||||
try:
|
||||
float(val)
|
||||
except:
|
||||
raise UserOptError(f'{val!r}: invalid {desc} (not a floating-point number)')
|
||||
die( 'UserOptError', f'{val!r}: invalid {desc} (not a floating-point number)' )
|
||||
|
||||
def opt_is_in_list(val,tlist,desc):
|
||||
if val not in tlist:
|
||||
q,sep = (('',','),("'","','"))[type(tlist[0]) == str]
|
||||
raise UserOptError('{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format(
|
||||
die( 'UserOptError', '{q}{v}{q}: invalid {w}\nValid choices: {q}{o}{q}'.format(
|
||||
v = val,
|
||||
w = desc,
|
||||
q = q,
|
||||
o = sep.join(map(str,sorted(tlist))) ))
|
||||
|
||||
def opt_unrecognized(key,val,desc='value'):
|
||||
raise UserOptError(f'{val!r}: unrecognized {desc} for option {fmt_opt(key)!r}')
|
||||
die( 'UserOptError', f'{val!r}: unrecognized {desc} for option {fmt_opt(key)!r}' )
|
||||
|
||||
def opt_display(key,val='',beg='For selected',end=':\n'):
|
||||
from .util import msg_r
|
||||
|
|
@ -475,15 +476,15 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
if key == 'out_fmt':
|
||||
p = 'hidden_incog_output_params'
|
||||
if sstype == IncogWalletHidden and not getattr(opt,p):
|
||||
raise UserOptError(
|
||||
die( 'UserOptError',
|
||||
'Hidden incog format output requested. ' +
|
||||
f'You must supply a file and offset with the {fmt_opt(p)!r} option' )
|
||||
if issubclass(sstype,IncogWallet) and opt.old_incog_fmt:
|
||||
opt_display(key,val,beg='Selected',end=' ')
|
||||
opt_display('old_incog_fmt',beg='conflicts with',end=':\n')
|
||||
raise UserOptError('Export to old incog wallet format unsupported')
|
||||
die( 'UserOptError', 'Export to old incog wallet format unsupported' )
|
||||
elif issubclass(sstype,Brainwallet):
|
||||
raise UserOptError('Output to brainwallet format unsupported')
|
||||
die( 'UserOptError', 'Output to brainwallet format unsupported' )
|
||||
|
||||
chk_out_fmt = chk_in_fmt
|
||||
|
||||
|
|
@ -491,7 +492,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
a = val.rsplit(',',1) # permit comma in filename
|
||||
if len(a) != 2:
|
||||
opt_display(key,val)
|
||||
raise UserOptError('Option requires two comma-separated arguments')
|
||||
die( 'UserOptError', 'Option requires two comma-separated arguments' )
|
||||
|
||||
fn,offset = a
|
||||
opt_is_int(offset,desc)
|
||||
|
|
@ -514,7 +515,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
val2 = getattr(opt,key2)
|
||||
from .wallet import IncogWalletHidden
|
||||
if val2 and val2 not in IncogWalletHidden.fmt_codes:
|
||||
raise UserOptError(f'Option conflict:\n {fmt_opt(key)}, with\n {fmt_opt(key2)}={val2}')
|
||||
die( 'UserOptError', f'Option conflict:\n {fmt_opt(key)}, with\n {fmt_opt(key2)}={val2}' )
|
||||
|
||||
chk_hidden_incog_output_params = chk_hidden_incog_input_params
|
||||
|
||||
|
|
@ -539,7 +540,7 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
a = val.split(',')
|
||||
if len(a) != 2:
|
||||
opt_display(key,val)
|
||||
raise UserOptError('Option requires two comma-separated arguments')
|
||||
die( 'UserOptError', 'Option requires two comma-separated arguments' )
|
||||
opt_is_int(a[0],'seed length '+desc)
|
||||
opt_is_in_list(int(a[0]),Seed.lens,'seed length '+desc)
|
||||
opt_is_in_list(a[1],list(hash_presets.keys()),'hash preset '+desc)
|
||||
|
|
@ -567,14 +568,14 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
# TODO: move this check elsewhere
|
||||
# def chk_rbf(key,val,desc):
|
||||
# if not proto.cap('rbf'):
|
||||
# raise UserOptError(f'--rbf requested, but {proto.coin} does not support replace-by-fee transactions')
|
||||
# die( 'UserOptError', f'--rbf requested, but {proto.coin} does not support replace-by-fee transactions' )
|
||||
|
||||
# def chk_bob(key,val,desc):
|
||||
# from .regtest import MMGenRegtest
|
||||
# try:
|
||||
# os.stat(os.path.join(MMGenRegtest(g.coin).d.datadir,'regtest','debug.log'))
|
||||
# except:
|
||||
# raise UserOptError(
|
||||
# die( 'UserOptError',
|
||||
# 'Regtest (Bob and Alice) mode not set up yet. ' +
|
||||
# f"Run '{g.proj_name.lower()}-regtest setup' to initialize." )
|
||||
#
|
||||
|
|
@ -587,13 +588,13 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
# TODO: move this check elsewhere
|
||||
# def chk_token(key,val,desc):
|
||||
# if not 'token' in proto.caps:
|
||||
# raise UserOptError(f'Coin {tx.coin!r} does not support the --token option')
|
||||
# die( 'UserOptError', f'Coin {tx.coin!r} does not support the --token option' )
|
||||
# if len(val) == 40 and is_hex_str(val):
|
||||
# return
|
||||
# if len(val) > 20 or not all(s.isalnum() for s in val):
|
||||
# raise UserOptError(f'{val!r}: invalid parameter for --token option')
|
||||
# die( 'UserOptError', f'{val!r}: invalid parameter for --token option' )
|
||||
|
||||
from .util import is_int
|
||||
from .util import is_int,die
|
||||
|
||||
cfuncs = { k:v for k,v in locals().items() if k.startswith('chk_') }
|
||||
|
||||
|
|
@ -642,8 +643,8 @@ def check_and_set_autoset_opts(): # Raises exception if any check fails
|
|||
else:
|
||||
ret = locals()[asd.type](key,val,asd)
|
||||
if type(ret) is str:
|
||||
from .util import fmt_list
|
||||
raise UserOptError(
|
||||
from .util import fmt_list,die
|
||||
die( 'UserOptError',
|
||||
'{!r}: invalid parameter for option --{} (not {}: {})'.format(
|
||||
val,
|
||||
key.replace('_','-'),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ passwdlist.py: Password list class for the MMGen suite
|
|||
|
||||
from collections import namedtuple
|
||||
|
||||
from .util import ymsg,is_int,keypress_confirm
|
||||
from .util import ymsg,is_int,keypress_confirm,die
|
||||
from .obj import ImmutableAttr,ListItemAttr,MMGenPWIDString,TwComment
|
||||
from .key import PrivKey
|
||||
from .addr import MMGenPasswordType,AddrIdx,AddrListID
|
||||
|
|
@ -112,8 +112,7 @@ class PasswordList(AddrList):
|
|||
self.pw_fmt = pw_fmt
|
||||
self.pw_fmt_disp = pw_fmt
|
||||
if self.pw_fmt not in self.pw_info:
|
||||
from .exception import InvalidPasswdFormat
|
||||
raise InvalidPasswdFormat(
|
||||
die( 'InvalidPasswdFormat',
|
||||
'{!r}: invalid password format. Valid formats: {}'.format(
|
||||
self.pw_fmt,
|
||||
', '.join(self.pw_info) ))
|
||||
|
|
|
|||
13
mmgen/rpc.py
13
mmgen/rpc.py
|
|
@ -190,7 +190,7 @@ class RPCBackends:
|
|||
headers = self.http_hdrs )
|
||||
r = s.getresponse() # => http.client.HTTPResponse instance
|
||||
except Exception as e:
|
||||
raise RPCFailure(str(e))
|
||||
die( 'RPCFailure', str(e) )
|
||||
|
||||
if timeout:
|
||||
ret = ( r.read(), r.status )
|
||||
|
|
@ -303,8 +303,7 @@ class RPCClient(MMGenObject):
|
|||
try:
|
||||
socket.create_connection((host,port),timeout=1).close()
|
||||
except:
|
||||
from .exception import SocketError
|
||||
raise SocketError(f'Unable to connect to {host}:{port}')
|
||||
die( 'SocketError', f'Unable to connect to {host}:{port}' )
|
||||
|
||||
self.http_hdrs = { 'Content-Type': 'application/json' }
|
||||
self.url = f'{self.network_proto}://{host}:{port}{self.host_path}'
|
||||
|
|
@ -435,7 +434,7 @@ class RPCClient(MMGenObject):
|
|||
except:
|
||||
try: m = t['error']
|
||||
except: m = t
|
||||
raise RPCFailure(m)
|
||||
die( 'RPCFailure', m )
|
||||
else:
|
||||
import http
|
||||
m,s = ( '', http.HTTPStatus(status) )
|
||||
|
|
@ -445,7 +444,7 @@ class RPCClient(MMGenObject):
|
|||
except:
|
||||
try: m = text.decode()
|
||||
except: m = text
|
||||
raise RPCFailure(f'{s.value} {s.name}: {m}')
|
||||
die( 'RPCFailure', f'{s.value} {s.name}: {m}' )
|
||||
|
||||
async def stop_daemon(self,quiet=False,silent=False):
|
||||
if self.daemon.state == 'ready':
|
||||
|
|
@ -852,10 +851,10 @@ async def rpc_init(proto,backend=None,daemon=None,ignore_daemon_version=False):
|
|||
ignore_daemon_version or proto.ignore_daemon_version or g.ignore_daemon_version )
|
||||
|
||||
if rpc.chain not in proto.chain_names:
|
||||
raise RPCChainMismatch('\n'+fmt(f"""
|
||||
die( 'RPCChainMismatch', '\n' + fmt(f"""
|
||||
Protocol: {proto.cls_name}
|
||||
Valid chain names: {fmt_list(proto.chain_names,fmt='bare')}
|
||||
RPC client chain: {rpc.chain}
|
||||
""",indent=' ').rstrip())
|
||||
""",indent=' ').rstrip() )
|
||||
|
||||
return rpc
|
||||
|
|
|
|||
|
|
@ -80,8 +80,7 @@ class SeedShareList(SubSeedList):
|
|||
msg(f'master_share seed ID collision with parent seed, incrementing nonce to {nonce+1}')
|
||||
else:
|
||||
return ms
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('nonce range exceeded')
|
||||
die( 'SubSeedNonceRangeExceeded', 'nonce range exceeded' )
|
||||
|
||||
def last_share_debug(last_share):
|
||||
if not debug_last_share:
|
||||
|
|
@ -109,8 +108,7 @@ class SeedShareList(SubSeedList):
|
|||
self.data['long'][ls.sid] = (count,nonce)
|
||||
break
|
||||
else:
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('nonce range exceeded')
|
||||
die( 'SubSeedNonceRangeExceeded', 'nonce range exceeded' )
|
||||
|
||||
if g.debug_subseed:
|
||||
A = parent_seed.data
|
||||
|
|
@ -119,8 +117,7 @@ class SeedShareList(SubSeedList):
|
|||
|
||||
def get_share_by_idx(self,idx,base_seed=False):
|
||||
if idx < 1 or idx > self.count:
|
||||
from .exception import RangeError
|
||||
raise RangeError(f'{idx}: share index out of range')
|
||||
die( 'RangeError', f'{idx}: share index out of range' )
|
||||
elif idx == self.count:
|
||||
return self.last_share
|
||||
elif self.master_share and idx == 1:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ subseed.py: Subseed classes and methods for the MMGen suite
|
|||
"""
|
||||
|
||||
from .color import green
|
||||
from .util import msg_r,msg,qmsg
|
||||
from .util import msg_r,msg,qmsg,die
|
||||
from .obj import MMGenRange,IndexedDict
|
||||
from .seed import *
|
||||
from .crypto import scramble_seed
|
||||
|
|
@ -191,8 +191,7 @@ class SubSeedList(MMGenObject):
|
|||
self.data[length][sid] = (idx,nonce)
|
||||
return last_sid == sid
|
||||
else: # must exit here, as this could leave self.data in inconsistent state
|
||||
from .exception import SubSeedNonceRangeExceeded
|
||||
raise SubSeedNonceRangeExceeded('add_subseed(): nonce range exceeded')
|
||||
die( 'SubSeedNonceRangeExceeded', 'add_subseed(): nonce range exceeded' )
|
||||
|
||||
for idx in SubSeedIdxRange(first_idx,last_idx).iterate():
|
||||
match1 = add_subseed(idx,'long')
|
||||
|
|
|
|||
13
mmgen/tw.py
13
mmgen/tw.py
|
|
@ -22,7 +22,6 @@ tw: Tracking wallet dependency classes for the MMGen suite
|
|||
|
||||
import time
|
||||
|
||||
from .exception import BadTwLabel,BadTwComment
|
||||
from .objmethods import Hilite,InitErrors,MMGenObject
|
||||
from .obj import TwComment
|
||||
from .addr import MMGenID
|
||||
|
|
@ -86,8 +85,8 @@ class TwMMGenID(str,Hilite,InitErrors,MMGenObject):
|
|||
|
||||
# non-displaying container for TwMMGenID,TwComment
|
||||
class TwLabel(str,InitErrors,MMGenObject):
|
||||
exc = BadTwLabel
|
||||
passthru_excs = (BadTwComment,)
|
||||
exc = 'BadTwLabel'
|
||||
passthru_excs = ('BadTwComment',)
|
||||
def __new__(cls,proto,text):
|
||||
if type(text) == cls:
|
||||
return text
|
||||
|
|
@ -109,8 +108,8 @@ def get_tw_label(proto,s):
|
|||
"""
|
||||
try:
|
||||
return TwLabel(proto,s)
|
||||
except BadTwComment:
|
||||
raise
|
||||
except Exception as e:
|
||||
# print(e)
|
||||
return None
|
||||
if type(e).__name__ == 'BadTwComment': # do it this way to avoid importing .exception
|
||||
raise
|
||||
else:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -126,8 +126,7 @@ class TwAddrList(MMGenDict,TwCommon,metaclass=AsyncInit):
|
|||
if not self.has_age:
|
||||
show_age = False
|
||||
if age_fmt not in self.age_fmts:
|
||||
from .exception import BadAgeFormat
|
||||
raise BadAgeFormat(f'{age_fmt!r}: invalid age format (must be one of {self.age_fmts!r})')
|
||||
die( 'BadAgeFormat', f'{age_fmt!r}: invalid age format (must be one of {self.age_fmts!r})' )
|
||||
fs = '{mid}' + ('',' {addr}')[showbtcaddrs] + ' {cmt} {amt}' + ('',' {age}')[show_age]
|
||||
mmaddrs = [k for k in self.keys() if k.type == 'mmgen']
|
||||
max_mmid_len = max(len(k) for k in mmaddrs) + 2 if mmaddrs else 10
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ twctl: Tracking wallet control class for the MMGen suite
|
|||
"""
|
||||
|
||||
from .globalvars import g
|
||||
from .util import msg,dmsg,write_mode,base_proto_subclass
|
||||
from .util import msg,dmsg,write_mode,base_proto_subclass,die
|
||||
from .base_obj import AsyncInit
|
||||
from .objmethods import MMGenObject
|
||||
from .obj import TwComment,get_obj
|
||||
|
|
@ -61,8 +61,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
|
|||
self.init_empty()
|
||||
|
||||
if self.data['coin'] != self.proto.coin: # TODO remove?
|
||||
from .exception import WalletFileError
|
||||
raise WalletFileError(
|
||||
die( 'WalletFileError',
|
||||
'Tracking wallet coin ({}) does not match current coin ({})!'.format(
|
||||
self.data['coin'],
|
||||
self.proto.coin ))
|
||||
|
|
@ -98,8 +97,7 @@ class TrackingWallet(MMGenObject,metaclass=AsyncInit):
|
|||
self.init_empty()
|
||||
self.force_write()
|
||||
else:
|
||||
from .exception import WalletFileError
|
||||
raise WalletFileError(f'File {self.tw_fn!r} exists but does not contain valid json data')
|
||||
die( 'WalletFileError', f'File {self.tw_fn!r} exists but does not contain valid json data' )
|
||||
else:
|
||||
self.upgrade_wallet_maybe()
|
||||
|
||||
|
|
|
|||
|
|
@ -128,8 +128,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view, add [l]abel:
|
|||
@age_fmt.setter
|
||||
def age_fmt(self,val):
|
||||
if val not in self.age_fmts:
|
||||
from .exception import BadAgeFormat
|
||||
raise BadAgeFormat(f'{val!r}: invalid age format (must be one of {self.age_fmts!r})')
|
||||
die( 'BadAgeFormat', f'{val!r}: invalid age format (must be one of {self.age_fmts!r})' )
|
||||
self._age_fmt = val
|
||||
|
||||
def get_display_precision(self):
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from ..globalvars import *
|
|||
from ..objmethods import MMGenObject
|
||||
from ..obj import ImmutableAttr,ListItemAttr,MMGenListItem,MMGenTxLabel,TwComment,CoinTxID,HexStr
|
||||
from ..addr import MMGenID,CoinAddr
|
||||
from ..util import msg,ymsg,fmt,remove_dups,keypress_confirm,make_timestamp,line_input
|
||||
from ..util import msg,ymsg,fmt,remove_dups,keypress_confirm,make_timestamp,line_input,die
|
||||
from ..opts import opt
|
||||
|
||||
class MMGenTxIO(MMGenListItem):
|
||||
|
|
@ -118,8 +118,8 @@ class Base(MMGenObject):
|
|||
def check_correct_chain(self):
|
||||
if hasattr(self,'rpc'):
|
||||
if self.chain != self.rpc.chain:
|
||||
raise TransactionChainMismatch(
|
||||
f'Transaction is for {self.chain}, but coin daemon chain is {self.rpc.chain}!')
|
||||
die( 'TransactionChainMismatch',
|
||||
f'Transaction is for {self.chain}, but coin daemon chain is {self.rpc.chain}!' )
|
||||
|
||||
def sum_inputs(self):
|
||||
return sum(e.amt for e in self.inputs)
|
||||
|
|
@ -177,7 +177,7 @@ class Base(MMGenObject):
|
|||
m = fs.format('\n '.join(non_mmaddrs))
|
||||
if caller in ('txdo','txsign'):
|
||||
if not opt.keys_from_file:
|
||||
raise UserOptError(f'\n{indent}ERROR: {m}\n')
|
||||
die( 'UserOptError', f'\n{indent}ERROR: {m}\n' )
|
||||
else:
|
||||
msg(f'\n{indent}WARNING: {m}\n')
|
||||
if not (opt.yes or keypress_confirm('Continue?',default_yes=True)):
|
||||
|
|
|
|||
|
|
@ -60,8 +60,7 @@ class MMGenTxFile(MMGenObject):
|
|||
try:
|
||||
desc = 'data'
|
||||
if len(tx_data) > g.max_tx_file_size:
|
||||
from .exception import MaxFileSizeExceeded
|
||||
raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
|
||||
die( 'MaxFileSizeExceeded', f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)' )
|
||||
tx_data = tx_data.splitlines()
|
||||
assert len(tx_data) >= 5,'number of lines less than 5'
|
||||
assert len(tx_data[0]) == 6,'invalid length of first line'
|
||||
|
|
@ -187,8 +186,7 @@ class MMGenTxFile(MMGenObject):
|
|||
self.chksum = make_chksum_6(' '.join(lines))
|
||||
fmt_data = '\n'.join([self.chksum] + lines) + '\n'
|
||||
if len(fmt_data) > g.max_tx_file_size:
|
||||
from .exception import MaxFileSizeExceeded
|
||||
raise MaxFileSizeExceeded(f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)')
|
||||
die( 'MaxFileSizeExceeded', f'Transaction file size exceeds limit ({g.max_tx_file_size} bytes)' )
|
||||
return fmt_data
|
||||
|
||||
def write(self,
|
||||
|
|
|
|||
|
|
@ -121,12 +121,17 @@ def mdie(*args):
|
|||
sys.exit(0)
|
||||
|
||||
def die(ev,s='',stdout=False):
|
||||
assert isinstance(ev,int)
|
||||
from .exception import MMGenSystemExit,MMGenError
|
||||
if ev <= 2:
|
||||
raise MMGenSystemExit(ev,s,stdout)
|
||||
if isinstance(ev,int):
|
||||
from .exception import MMGenSystemExit,MMGenError
|
||||
if ev <= 2:
|
||||
raise MMGenSystemExit(ev,s,stdout)
|
||||
else:
|
||||
raise MMGenError(ev,s,stdout)
|
||||
elif isinstance(ev,str):
|
||||
import mmgen.exception
|
||||
raise getattr(mmgen.exception,ev)(s)
|
||||
else:
|
||||
raise MMGenError(ev,s,stdout)
|
||||
raise ValueError(f'{ev}: exit value must be string or int instance')
|
||||
|
||||
def die_wait(delay,ev=0,s=''):
|
||||
assert isinstance(delay,int)
|
||||
|
|
@ -460,8 +465,7 @@ def compare_or_die(val1, desc1, val2, desc2, e='Error'):
|
|||
def check_wallet_extension(fn):
|
||||
from .wallet import Wallet
|
||||
if not Wallet.ext_to_type(get_extension(fn)):
|
||||
from .exception import BadFileExtension
|
||||
raise BadFileExtension(f'{fn!r}: unrecognized seed source file extension')
|
||||
die( 'BadFileExtension', f'{fn!r}: unrecognized seed source file extension' )
|
||||
|
||||
def make_full_path(outdir,outfile):
|
||||
return os.path.normpath(os.path.join(outdir, os.path.basename(outfile)))
|
||||
|
|
@ -472,8 +476,7 @@ def confirm_or_raise(message,q,expect='YES',exit_msg='Exiting at user request'):
|
|||
a = f'{q} ' if q[0].isupper() else f'Are you sure you want to {q}?\n'
|
||||
b = f'Type uppercase {expect!r} to confirm: '
|
||||
if line_input(a+b).strip() != expect:
|
||||
from .exception import UserNonConfirmation
|
||||
raise UserNonConfirmation(exit_msg)
|
||||
die( 'UserNonConfirmation', exit_msg )
|
||||
|
||||
def get_words_from_user(prompt):
|
||||
words = line_input(prompt, echo=opt.echo_passphrase).split()
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ class DieRollSeedFile(WalletUnenc):
|
|||
rmap = bc.seedlen_map_rev
|
||||
|
||||
if not len(d) in rmap:
|
||||
raise SeedLengthError('{!r}: invalid length for {} (must be one of {})'.format(
|
||||
die( 'SeedLengthError', '{!r}: invalid length for {} (must be one of {})'.format(
|
||||
len(d),
|
||||
self.desc,
|
||||
list(rmap) ))
|
||||
|
|
|
|||
|
|
@ -54,17 +54,15 @@ class xmrseed(baseconv):
|
|||
wl = self.digits
|
||||
base = len(wl)
|
||||
|
||||
from .exception import MnemonicError
|
||||
|
||||
if not set(words) <= set(wl):
|
||||
raise MnemonicError( f'{words!r}: not in {desc} format' )
|
||||
die( 'MnemonicError', f'{words!r}: not in {desc} format' )
|
||||
|
||||
if len(words) not in self.seedlen_map_rev:
|
||||
raise MnemonicError( f'{len(words)}: invalid seed phrase length for {desc}' )
|
||||
die( 'MnemonicError', f'{len(words)}: invalid seed phrase length for {desc}' )
|
||||
|
||||
z = self.monero_mn_checksum(words[:-1])
|
||||
if z != words[-1]:
|
||||
raise MnemonicError(f'invalid {desc} checksum')
|
||||
die( 'MnemonicError', f'invalid {desc} checksum' )
|
||||
|
||||
words = tuple(words[:-1])
|
||||
|
||||
|
|
@ -84,8 +82,7 @@ class xmrseed(baseconv):
|
|||
base = len(wl)
|
||||
|
||||
if len(bytestr) not in self.seedlen_map:
|
||||
from .exception import SeedLengthError
|
||||
raise SeedLengthError(f'{len(bytestr)}: invalid seed byte length for {desc}')
|
||||
die( 'SeedLengthError', f'{len(bytestr)}: invalid seed byte length for {desc}' )
|
||||
|
||||
def num2base_monero(num):
|
||||
w1 = num % base
|
||||
|
|
|
|||
|
|
@ -888,6 +888,6 @@ class MoneroWalletOps:
|
|||
ymsg('Transaction not relayed')
|
||||
return True
|
||||
else:
|
||||
raise RPCFailure(repr(res))
|
||||
die( 'RPCFailure', repr(res) )
|
||||
else:
|
||||
die(1,'Exiting at user request')
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ def cleandir(d,do_msg=False):
|
|||
def mk_tmpdir(d):
|
||||
try: os.mkdir(d,0o755)
|
||||
except OSError as e:
|
||||
if e.errno != 17: raise
|
||||
if e.errno != 17:
|
||||
raise
|
||||
else:
|
||||
vmsg(f'Created directory {d!r}')
|
||||
|
||||
|
|
@ -149,7 +150,7 @@ def ok():
|
|||
|
||||
def cmp_or_die(s,t,desc=None):
|
||||
if s != t:
|
||||
raise TestSuiteFatalException(
|
||||
die( 'TestSuiteFatalException',
|
||||
(f'For {desc}:\n' if desc else '') +
|
||||
f'ERROR: recoded data:\n{t!r}\ndiffers from original data:\n{s!r}'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ def test_attr_perm(obj,attrname,perm_name,perm_value,dobj,attrval_type):
|
|||
try:
|
||||
so = sample_objs[attrval_type.__name__]
|
||||
except:
|
||||
raise SampleObjError(f'unable to find sample object of type {attrval_type.__name__!r}')
|
||||
die( 'SampleObjError', f'unable to find sample object of type {attrval_type.__name__!r}' )
|
||||
# ListItemAttr allows setting an attribute if its value is None
|
||||
if type(dobj) == ListItemAttr and getattr(obj,attrname) == None:
|
||||
setattr(obj,attrname,so)
|
||||
|
|
|
|||
|
|
@ -460,7 +460,8 @@ def create_tmp_dirs(shm_dir):
|
|||
try:
|
||||
os.unlink(cfgs[cfg]['tmpdir'])
|
||||
except OSError as e:
|
||||
if e.errno != 2: raise
|
||||
if e.errno != 2:
|
||||
raise
|
||||
finally:
|
||||
os.symlink(src,cfgs[cfg]['tmpdir'])
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ from subprocess import run,PIPE,DEVNULL
|
|||
from mmgen.globalvars import g
|
||||
from mmgen.opts import opt
|
||||
from mmgen.util import die
|
||||
from mmgen.exception import *
|
||||
from mmgen.amt import ETHAmt
|
||||
from mmgen.protocol import CoinProtocol
|
||||
from ..include.common import *
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ def make_brainwallet_file(fn):
|
|||
def verify_checksum_or_exit(checksum,chk):
|
||||
chk = strip_ansi_escapes(chk)
|
||||
if checksum != chk:
|
||||
raise TestSuiteFatalException(f'Checksum error: {chk}')
|
||||
die( 'TestSuiteFatalException', f'Checksum error: {chk}' )
|
||||
vmsg(green('Checksums match: ') + cyan(chk))
|
||||
|
||||
addrs_per_wallet = 8
|
||||
|
|
@ -403,7 +403,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
ad.add(al)
|
||||
aix = AddrIdxList(fmt_str=self.cfgs[s]['addr_idx_list'])
|
||||
if len(aix) != addrs_per_wallet:
|
||||
raise TestSuiteFatalException(f'Address index list length != {addrs_per_wallet}: {repr(aix)}')
|
||||
die( 'TestSuiteFatalException', f'Address index list length != {addrs_per_wallet}: {repr(aix)}' )
|
||||
tx_data[s] = {
|
||||
'addrfile': afile,
|
||||
'chk': al.chksum,
|
||||
|
|
@ -497,7 +497,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared):
|
|||
['-f',self.tx_fee,'-B'] + add_args + cmd_args + txdo_args)
|
||||
|
||||
if t.expect([('Get','Unsigned transac')[cmdline_inputs],r'Unable to connect to \S+'],regex=True) == 1:
|
||||
raise TestSuiteException('\n'+t.p.after)
|
||||
die( 'TestSuiteException', '\n'+t.p.after )
|
||||
|
||||
if cmdline_inputs:
|
||||
t.written_to_file('tion')
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ class TestSuiteHelp(TestSuiteBase):
|
|||
|
||||
def usage(self):
|
||||
t = self.spawn(f'mmgen-walletgen',['foo'])
|
||||
t.expect('USAGE: mmgen-walletgen')
|
||||
t.expect('MMGenSystemExit(1)')
|
||||
t.expect('USAGE: mmgen-walletgen')
|
||||
t.req_exit_val = 1
|
||||
return t
|
||||
|
||||
|
|
|
|||
|
|
@ -778,7 +778,7 @@ def fork_cmd(cmd_name,args,out,opts,stdin_input):
|
|||
vmsg(cp.stderr.strip().decode())
|
||||
if cp.returncode != 0:
|
||||
import re
|
||||
m = re.match(b'tool command returned (None|False)'+NL.encode(),cp.stderr)
|
||||
m = re.search(b'tool command returned (None|False)',cp.stdout)
|
||||
if m:
|
||||
return { b'None': None, b'False': False }[m.group(1)]
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test/unit_tests_d/ut_baseconv.py: Base conversion unit test for the MMGen suite
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
|
||||
class unit_test(object):
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test/unit_tests_d/ut_bip39: BIP39 unit test for the MMGen suite
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
|
||||
class unit_test(object):
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ test/unit_tests_d/ut_daemon.py: unit test for the MMGen suite's Daemon class
|
|||
|
||||
from subprocess import run,DEVNULL
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
from mmgen.daemon import *
|
||||
from mmgen.protocol import init_proto
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test/unit_tests_d/ut_flags.py: unit test for the MMGen suite's ClassFlags class
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
from mmgen.flags import *
|
||||
|
||||
class unit_test(object):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test/unit_tests_d/ut_lockable.py: unit test for the MMGen suite's Lockable class
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
|
||||
class unit_test(object):
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test.unit_tests_d.ut_rpc: RPC unit test for the MMGen suite
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
|
||||
from mmgen.protocol import init_proto
|
||||
from mmgen.rpc import rpc_init,MoneroWalletRPCClient
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ test/unit_tests_d/ut_xmrseed: Monero mnemonic unit test for the MMGen suite
|
|||
"""
|
||||
|
||||
from mmgen.common import *
|
||||
from mmgen.exception import *
|
||||
|
||||
class unit_test(object):
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue