new Lockable class; lock global vars after initialization (amended)
This commit is contained in:
parent
973c7be78d
commit
4c2410e0d6
25 changed files with 422 additions and 206 deletions
|
|
@ -244,7 +244,7 @@ Actions: [q]uit view, [p]rint to file, pager [v]iew, [w]ide view,
|
|||
'l':'a_lbl_add','D':'a_addr_delete','R':'a_balance_refresh' }
|
||||
|
||||
async def __ainit__(self,proto,*args,**kwargs):
|
||||
if g.use_cached_balances:
|
||||
if g.cached_balances:
|
||||
self.hdr_fmt += '\n' + yellow('WARNING: Using cached balances. These may be out of date!')
|
||||
await TwUnspentOutputs.__ainit__(self,proto,*args,**kwargs)
|
||||
|
||||
|
|
|
|||
88
mmgen/base_obj.py
Executable file
88
mmgen/base_obj.py
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
|
||||
# Copyright (C)2013-2020 The MMGen Project <mmgen@tuta.io>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
base_obj.py: base objects with no internal imports for the MMGen suite
|
||||
"""
|
||||
|
||||
class AttrCtrl:
|
||||
"""
|
||||
After instance is locked, forbid setting any attribute if the attribute is not present
|
||||
in either the class or instance dict.
|
||||
|
||||
If _use_class_attr is True, ensure that attribute's type matches that of the class
|
||||
attribute, unless the class attribute is set to None, in which case no type checking
|
||||
is performed.
|
||||
"""
|
||||
_lock = False
|
||||
_use_class_attr = False
|
||||
|
||||
def lock(self):
|
||||
self._lock = True
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
if self._lock:
|
||||
def do_error(name,value,ref_val):
|
||||
raise AttributeError(
|
||||
f'{value!r}: invalid value for attribute {name!r}'
|
||||
+ ' of {} object (must be of type {}, not {})'.format(
|
||||
type(self).__name__,
|
||||
type(ref_val).__name__,
|
||||
type(value).__name__ ) )
|
||||
|
||||
if not hasattr(self,name):
|
||||
raise AttributeError(f'{type(self).__name__} object has no attribute {name!r}')
|
||||
|
||||
ref_val = getattr(type(self),name) if self._use_class_attr else getattr(self,name)
|
||||
|
||||
if (ref_val is not None) and not isinstance(value,type(ref_val)):
|
||||
do_error(name,value,ref_val)
|
||||
|
||||
return object.__setattr__(self,name,value)
|
||||
|
||||
def __delattr__(self,name,value):
|
||||
raise AttributeError('attribute cannot be deleted')
|
||||
|
||||
class Lockable(AttrCtrl):
|
||||
"""
|
||||
After instance is locked, its attributes become read-only, with the following exceptions:
|
||||
- if the attribute's name is in _set_ok, attr can be set once after locking, if unset
|
||||
- if the attribute's name is in _reset_ok, read-only restrictions are bypassed and only
|
||||
AttrCtrl checking is performed
|
||||
|
||||
To determine whether an attribute is set, it's matched against either None or the class attribute,
|
||||
if _use_class_attr is True
|
||||
"""
|
||||
_set_ok = ()
|
||||
_reset_ok = ()
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
if self._lock and hasattr(self,name):
|
||||
if name not in (self._set_ok + self._reset_ok):
|
||||
raise AttributeError(f'attribute {name!r} of {type(self).__name__} object is read-only')
|
||||
elif name not in self._reset_ok:
|
||||
#print(self.__dict__)
|
||||
if not (
|
||||
getattr(self,name) is None or
|
||||
( self._use_class_attr and name not in self.__dict__ ) ):
|
||||
raise AttributeError(
|
||||
f'attribute {name!r} of {type(self).__name__} object is already set,'
|
||||
+ ' and resetting is forbidden' )
|
||||
# name is in (_set_ok + _reset_ok) -- allow name to be in both lists
|
||||
|
||||
return AttrCtrl.__setattr__(self,name,value)
|
||||
|
|
@ -216,14 +216,44 @@ def get_hash_preset_from_user(hp=g.dfl_hash_preset,desc='data'):
|
|||
else:
|
||||
return hp
|
||||
|
||||
_salt_len,_sha256_len,_nonce_len = 32,32,32
|
||||
def get_new_passphrase(desc,passchg=False):
|
||||
|
||||
w = '{}passphrase for {}'.format(('','new ')[bool(passchg)], desc)
|
||||
if opt.passwd_file:
|
||||
pw = ' '.join(get_words_from_file(opt.passwd_file,w))
|
||||
elif opt.echo_passphrase:
|
||||
pw = ' '.join(get_words_from_user(f'Enter {w}: '))
|
||||
else:
|
||||
for i in range(g.passwd_max_tries):
|
||||
pw = ' '.join(get_words_from_user(f'Enter {w}: '))
|
||||
pw_chk = ' '.join(get_words_from_user('Repeat passphrase: '))
|
||||
dmsg(f'Passphrases: [{pw}] [{pw_chk}]')
|
||||
if pw == pw_chk:
|
||||
vmsg('Passphrases match'); break
|
||||
else: msg('Passphrases do not match. Try again.')
|
||||
else:
|
||||
die(2,f'User failed to duplicate passphrase in {g.passwd_max_tries} attempts')
|
||||
|
||||
if pw == '':
|
||||
qmsg('WARNING: Empty passphrase')
|
||||
|
||||
return pw
|
||||
|
||||
def get_passphrase(desc,passchg=False):
|
||||
prompt ='Enter {}passphrase for {}: '.format(('','old ')[bool(passchg)],desc)
|
||||
if opt.passwd_file:
|
||||
pwfile_reuse_warning(opt.passwd_file)
|
||||
return ' '.join(get_words_from_file(opt.passwd_file,'passphrase'))
|
||||
else:
|
||||
return ' '.join(get_words_from_user(prompt))
|
||||
|
||||
_salt_len,_sha256_len,_nonce_len = (32,32,32)
|
||||
|
||||
def mmgen_encrypt(data,desc='data',hash_preset=''):
|
||||
salt = get_random(_salt_len)
|
||||
iv = get_random(g.aesctr_iv_len)
|
||||
nonce = get_random(_nonce_len)
|
||||
hp = hash_preset or (
|
||||
opt.hash_preset if 'hash_preset' in opt.set_by_user else get_hash_preset_from_user('3',desc))
|
||||
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user('3',desc)
|
||||
m = ('user-requested','default')[hp=='3']
|
||||
vmsg(f'Encrypting {desc}')
|
||||
qmsg(f'Using {m} hash preset of {hp!r}')
|
||||
|
|
@ -238,8 +268,7 @@ def mmgen_decrypt(data,desc='data',hash_preset=''):
|
|||
salt = data[:_salt_len]
|
||||
iv = data[_salt_len:dstart]
|
||||
enc_d = data[dstart:]
|
||||
hp = hash_preset or (
|
||||
opt.hash_preset if 'hash_preset' in opt.set_by_user else get_hash_preset_from_user('3',desc))
|
||||
hp = hash_preset or opt.hash_preset or get_hash_preset_from_user('3',desc)
|
||||
m = ('user-requested','default')[hp=='3']
|
||||
qmsg(f'Using {m} hash preset of {hp!r}')
|
||||
passwd = get_passphrase(desc)
|
||||
|
|
|
|||
|
|
@ -25,12 +25,14 @@ from decimal import Decimal
|
|||
from collections import namedtuple
|
||||
from .devtools import *
|
||||
|
||||
from .base_obj import Lockable
|
||||
|
||||
def die(exit_val,s=''):
|
||||
if s:
|
||||
sys.stderr.write(s+'\n')
|
||||
sys.exit(exit_val)
|
||||
|
||||
class GlobalContext:
|
||||
class GlobalContext(Lockable):
|
||||
"""
|
||||
Set global vars to default values
|
||||
Globals are overridden in this order:
|
||||
|
|
@ -38,6 +40,10 @@ class GlobalContext:
|
|||
2 - environmental vars
|
||||
3 - command line
|
||||
"""
|
||||
_set_ok = ('user_entropy','session')
|
||||
_reset_ok = ('stdout','stderr','accept_defaults')
|
||||
_use_class_attr = True
|
||||
|
||||
# Constants:
|
||||
version = '0.12.099'
|
||||
release_date = 'May 2020'
|
||||
|
|
@ -63,12 +69,12 @@ class GlobalContext:
|
|||
# Variables - these might be altered at runtime:
|
||||
|
||||
user_entropy = b''
|
||||
hash_preset = '3'
|
||||
dfl_hash_preset = '3'
|
||||
dfl_seed_len = 256
|
||||
usr_randchars = 30
|
||||
|
||||
tx_fee_adj = Decimal('1.0')
|
||||
tx_confs = 3
|
||||
seed_len = 256
|
||||
|
||||
# Constant vars - some of these might be overridden in opts.py, but they don't change thereafter
|
||||
|
||||
|
|
@ -97,7 +103,8 @@ class GlobalContext:
|
|||
monero_wallet_rpc_password = ''
|
||||
rpc_fail_on_command = ''
|
||||
aiohttp_rpc_queue_len = 16
|
||||
use_cached_balances = False
|
||||
session = None
|
||||
cached_balances = False
|
||||
|
||||
# regtest:
|
||||
bob = False
|
||||
|
|
@ -141,11 +148,12 @@ class GlobalContext:
|
|||
daemon_data_dir = '' # set by user
|
||||
|
||||
# global var sets user opt:
|
||||
global_sets_opt = ( 'minconf','seed_len','hash_preset','usr_randchars','debug',
|
||||
'quiet','tx_confs','tx_fee_adj','key_generator' )
|
||||
global_sets_opt = (
|
||||
'minconf','usr_randchars','debug', 'quiet','tx_confs','tx_fee_adj','key_generator' )
|
||||
|
||||
# user opt sets global var:
|
||||
opt_sets_global = ( 'use_internal_keccak_module','subseeds' )
|
||||
opt_sets_global = (
|
||||
'use_internal_keccak_module','subseeds','cached_balances' )
|
||||
|
||||
# 'long' opts - opt sets global var
|
||||
common_opts = (
|
||||
|
|
@ -160,7 +168,7 @@ class GlobalContext:
|
|||
'quiet','verbose','debug','outdir','echo_passphrase','passwd_file','stdout',
|
||||
'show_hash_presets','label','keep_passphrase','keep_hash_preset','yes',
|
||||
'brain_params','b16','usr_randchars','coin','bob','alice','key_generator',
|
||||
'hidden_incog_input_params','in_fmt'
|
||||
'hidden_incog_input_params','in_fmt','hash_preset','seed_len',
|
||||
)
|
||||
incompatible_opts = (
|
||||
('help','longhelp'),
|
||||
|
|
@ -229,6 +237,10 @@ class GlobalContext:
|
|||
if platform == 'win':
|
||||
autoset_opts['rpc_backend'].choices.remove('aiohttp')
|
||||
|
||||
auto_typeset_opts = {
|
||||
'seed_len': int,
|
||||
}
|
||||
|
||||
min_screen_width = 80
|
||||
minconf = 1
|
||||
max_tx_file_size = 100000
|
||||
|
|
@ -271,6 +283,9 @@ class GlobalContext:
|
|||
short_disp_timeout = 0.1
|
||||
if os.getenv('MMGEN_TEST_SUITE_POPEN_SPAWN'):
|
||||
stdin_tty = True
|
||||
if prog_name == 'unit_tests.py':
|
||||
_set_ok += ('debug_subseed',)
|
||||
_reset_ok += ('force_standalone_scrypt_module','session')
|
||||
|
||||
if os.getenv('MMGEN_DEBUG_ALL'):
|
||||
for name in env_opts:
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ opts_data = {
|
|||
Options: {kgs} (default: {kg})
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-z, --show-hash-presets Show information on available hash presets
|
||||
-P, --passwd-file= f Get wallet passphrase from file 'f'
|
||||
-q, --quiet Produce quieter output; suppress some warnings
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ wallet_dir = '/dev/shm/autosign'
|
|||
key_fn = 'autosign.key'
|
||||
|
||||
from .common import *
|
||||
opts.UserOpts._set_ok += ('outdir','passwd_file')
|
||||
|
||||
prog_name = os.path.basename(sys.argv[0])
|
||||
opts_data = {
|
||||
'sets': [('stealth_led', True, 'led', True)],
|
||||
|
|
@ -107,11 +109,22 @@ This command is currently available only on Linux-based platforms.
|
|||
}
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data,add_opts=['mmgen_keys_from_file','in_fmt'])
|
||||
cmd_args = opts.init(
|
||||
opts_data,
|
||||
add_opts = ['mmgen_keys_from_file','hidden_incog_input_params'],
|
||||
init_opts = {
|
||||
'quiet': True,
|
||||
'in_fmt': 'words',
|
||||
'out_fmt': 'wallet',
|
||||
'usr_randchars': 0,
|
||||
'hash_preset': '1',
|
||||
'label': 'Autosign Wallet',
|
||||
})
|
||||
|
||||
exit_if_mswin('autosigning')
|
||||
|
||||
import mmgen.tx
|
||||
from .wallet import Wallet
|
||||
from .txsign import txsign
|
||||
from .protocol import init_proto
|
||||
from .rpc import rpc_init
|
||||
|
|
@ -123,6 +136,7 @@ if opt.mountpoint:
|
|||
mountpoint = opt.mountpoint
|
||||
|
||||
opt.outdir = tx_dir = os.path.join(mountpoint,'tx')
|
||||
opt.passwd_file = os.path.join(tx_dir,key_fn)
|
||||
|
||||
async def check_daemons_running():
|
||||
if opt.coin:
|
||||
|
|
@ -220,15 +234,11 @@ async def sign():
|
|||
return True
|
||||
|
||||
def decrypt_wallets():
|
||||
opt.hash_preset = '1'
|
||||
opt.set_by_user = ['hash_preset']
|
||||
opt.passwd_file = os.path.join(tx_dir,key_fn)
|
||||
from .wallet import Wallet
|
||||
msg(f'Unlocking wallet{suf(wfs)} with key from {opt.passwd_file!r}')
|
||||
fails = 0
|
||||
for wf in wfs:
|
||||
try:
|
||||
Wallet(wf)
|
||||
Wallet(wf,ignore_in_fmt=True)
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
fails += 1
|
||||
|
|
@ -335,18 +345,7 @@ def create_wallet_dir():
|
|||
def setup():
|
||||
remove_wallet_dir()
|
||||
gen_key(no_unmount=True)
|
||||
from .wallet import Wallet
|
||||
opt.hidden_incog_input_params = None
|
||||
opt.quiet = True
|
||||
opt.in_fmt = 'words'
|
||||
ss_in = Wallet()
|
||||
opt.out_fmt = 'wallet'
|
||||
opt.usr_randchars = 0
|
||||
opt.hash_preset = '1'
|
||||
opt.set_by_user = ['hash_preset']
|
||||
opt.passwd_file = os.path.join(tx_dir,key_fn)
|
||||
from .obj import MMGenWalletLabel
|
||||
opt.label = MMGenWalletLabel('Autosign Wallet')
|
||||
ss_out = Wallet(ss=ss_in)
|
||||
ss_out.write_to_file(desc='autosign wallet',outdir=wallet_dir)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ opts_data = {
|
|||
generate passwords of half the default length.
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-z, --show-hash-presets Show information on available hash presets
|
||||
-P, --passwd-file= f Get wallet passphrase from file 'f'
|
||||
-q, --quiet Produce quieter output; suppress some warnings
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ opts_data = {
|
|||
-L, --label= l Specify a label 'l' for output wallet
|
||||
-M, --master-share=i Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-z, --show-hash-presets Show information on available hash presets
|
||||
-P, --passwd-file= f Get wallet passphrase from file 'f'
|
||||
-q, --quiet Produce quieter output; suppress some warnings
|
||||
|
|
@ -110,9 +110,6 @@ cmd_args = opts.init(opts_data)
|
|||
if len(cmd_args) + bool(opt.hidden_incog_input_params) < 2:
|
||||
opts.usage()
|
||||
|
||||
if opt.label:
|
||||
opt.label = MMGenWalletLabel(opt.label,msg="Error in option '--label'")
|
||||
|
||||
if opt.master_share:
|
||||
master_idx = MasterShareIdx(opt.master_share)
|
||||
id_str = SeedSplitIDString(opt.id_str or 'default')
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ opts_data = {
|
|||
--, --longhelp Print help message for long options (common options)
|
||||
-k, --use-internal-keccak-module Force use of the internal keccak module
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-P, --passwd-file= f Get passphrase from file 'f'.
|
||||
-q, --quiet Produce quieter output
|
||||
-r, --usr-randchars=n Get 'n' characters of additional randomness from
|
||||
|
|
@ -91,8 +91,6 @@ Type '{pn} help <command>' for help on a particular command
|
|||
|
||||
cmd_args = opts.init(opts_data,add_opts=['hidden_incog_input_params','in_fmt','use_old_ed25519'])
|
||||
|
||||
g.use_cached_balances = opt.cached_balances
|
||||
|
||||
if len(cmd_args) < 1:
|
||||
opts.usage()
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ opts_data = {
|
|||
-i, --in-fmt= f Input is from wallet format 'f' (see FMT CODES below)
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths.
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths.
|
||||
-k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
|
||||
-K, --key-generator= m Use method 'm' for public key generation
|
||||
Options: {kgs}
|
||||
|
|
@ -63,7 +63,7 @@ opts_data = {
|
|||
for the transaction's change output, if present)
|
||||
-O, --old-incog-fmt Specify old-format incognito input
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-P, --passwd-file= f Get {pnm} wallet or {dn} passphrase from file 'f'
|
||||
-q, --quiet Suppress warnings; overwrite files without prompting
|
||||
-s, --send Sign and send the transaction (the default if seed
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@ opts_data = {
|
|||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
||||
g.use_cached_balances = opt.cached_balances
|
||||
|
||||
async def main():
|
||||
|
||||
from .protocol import init_proto_from_opts
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ opts_data = {
|
|||
outputs associated with each address will be included.
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths.
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths.
|
||||
-k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
|
||||
-K, --key-generator= m Use method 'm' for public key generation
|
||||
Options: {kgs}
|
||||
|
|
@ -71,7 +71,7 @@ opts_data = {
|
|||
mappings, so the user should record its checksum.
|
||||
-O, --old-incog-fmt Specify old-format incognito input
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-P, --passwd-file= f Get {pnm} wallet passphrase from file 'f'
|
||||
-r, --rbf Make transaction BIP 125 (replace-by-fee) replaceable
|
||||
-q, --quiet Suppress warnings; overwrite files without prompting
|
||||
|
|
@ -114,8 +114,6 @@ column below:
|
|||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
||||
g.use_cached_balances = opt.cached_balances
|
||||
|
||||
from .tx import *
|
||||
from .txsign import *
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@ opts_data = {
|
|||
-O, --old-incog-fmt Specify old-format incognito input
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths.
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths.
|
||||
-p, --hash-preset=p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-z, --show-hash-presets Show information on available hash presets
|
||||
-k, --keys-from-file=f Provide additional keys for non-{pnm} addresses
|
||||
-K, --key-generator=m Use method 'm' for public key generation
|
||||
|
|
|
|||
|
|
@ -101,12 +101,12 @@ opts_data = {
|
|||
-K, --keep-hash-preset Reuse hash preset of input wallet for output wallet
|
||||
-l, --seed-len= l Specify wallet seed length of 'l' bits. This option
|
||||
is required only for brainwallet and incognito inputs
|
||||
with non-standard (< {g.seed_len}-bit) seed lengths.
|
||||
with non-standard (< {g.dfl_seed_len}-bit) seed lengths.
|
||||
-L, --label= l Specify a label 'l' for output wallet
|
||||
-m, --keep-label Reuse label of input wallet for output wallet
|
||||
-M, --master-share=i Use a master share with index 'i' (min:{ms_min}, max:{ms_max})
|
||||
-p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p'
|
||||
for password hashing (default: '{g.hash_preset}')
|
||||
for password hashing (default: '{g.dfl_hash_preset}')
|
||||
-z, --show-hash-presets Show information on available hash presets
|
||||
-P, --passwd-file= f Get wallet passphrase from file 'f'
|
||||
-q, --quiet Produce quieter output; suppress some warnings
|
||||
|
|
@ -144,9 +144,6 @@ FMT CODES:
|
|||
|
||||
cmd_args = opts.init(opts_data,opt_filter=opt_filter)
|
||||
|
||||
if opt.label:
|
||||
opt.label = MMGenWalletLabel(opt.label,msg="Error in option '--label'")
|
||||
|
||||
if invoked_as == 'subgen':
|
||||
from .obj import SubSeedIdx
|
||||
ss_idx = SubSeedIdx(cmd_args.pop())
|
||||
|
|
|
|||
|
|
@ -21,13 +21,17 @@ opts.py: MMGen-specific options processing after generic processing by share.Op
|
|||
"""
|
||||
import sys,os,stat
|
||||
|
||||
class opt_cls(object):
|
||||
pass
|
||||
opt = opt_cls()
|
||||
|
||||
from .exception import UserOptError
|
||||
from .globalvars import g
|
||||
from .base_obj import Lockable
|
||||
import mmgen.share.Opts
|
||||
|
||||
class UserOpts(Lockable):
|
||||
_set_ok = ('usr_randchars',)
|
||||
_reset_ok = ('quiet','verbose','yes')
|
||||
|
||||
opt = UserOpts()
|
||||
|
||||
from .util import *
|
||||
|
||||
def usage():
|
||||
|
|
@ -228,7 +232,7 @@ opts_data_dfl = {
|
|||
}
|
||||
}
|
||||
|
||||
def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
||||
def init(opts_data=None,add_opts=None,init_opts=None,opt_filter=None,parse_only=False):
|
||||
|
||||
if opts_data is None:
|
||||
opts_data = opts_data_dfl
|
||||
|
|
@ -238,6 +242,11 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
|||
# po: (user_opts,cmd_args,opts,skipped_opts)
|
||||
po = mmgen.share.Opts.parse_opts(opts_data,opt_filter=opt_filter,parse_only=parse_only)
|
||||
|
||||
if init_opts: # allow programs to preload user opts
|
||||
for uopt,val in init_opts.items():
|
||||
if uopt not in po.user_opts:
|
||||
po.user_opts[uopt] = val
|
||||
|
||||
if parse_only:
|
||||
return po
|
||||
|
||||
|
|
@ -248,7 +257,8 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
|||
for o in set(
|
||||
po.opts
|
||||
+ po.skipped_opts
|
||||
+ tuple(add_opts)
|
||||
+ tuple(add_opts or [])
|
||||
+ tuple(init_opts or [])
|
||||
+ g.required_opts
|
||||
+ g.common_opts ):
|
||||
setattr(opt,o,po.user_opts[o] if o in po.user_opts else None)
|
||||
|
|
@ -309,11 +319,9 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
|||
# Set user opts from globals:
|
||||
# - if opt is unset, set it to global value
|
||||
# - if opt is set, convert its type to that of global value
|
||||
opt.set_by_user = []
|
||||
for k in g.global_sets_opt:
|
||||
if hasattr(opt,k) and getattr(opt,k) != None:
|
||||
setattr(opt,k,set_for_type(getattr(opt,k),getattr(g,k),'--'+k))
|
||||
opt.set_by_user.append(k)
|
||||
else:
|
||||
setattr(opt,k,getattr(g,k))
|
||||
|
||||
|
|
@ -355,6 +363,8 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
|||
# Check all opts against g.autoset_opts, setting if unset
|
||||
check_and_set_autoset_opts()
|
||||
|
||||
set_auto_typeset_opts()
|
||||
|
||||
if opt.verbose:
|
||||
opt.quiet = None
|
||||
|
||||
|
|
@ -370,6 +380,9 @@ def init(opts_data=None,add_opts=[],opt_filter=None,parse_only=False):
|
|||
if k in opts_data:
|
||||
del opts_data[k]
|
||||
|
||||
g.lock()
|
||||
opt.lock()
|
||||
|
||||
return po.cmd_args
|
||||
|
||||
# DISABLED
|
||||
|
|
@ -575,6 +588,13 @@ def check_usr_opts(usr_opts): # Raises an exception if any check fails
|
|||
elif g.debug:
|
||||
Msg('check_usr_opts(): No test for opt {!r}'.format(key))
|
||||
|
||||
def set_auto_typeset_opts():
|
||||
for key,ref_type in g.auto_typeset_opts.items():
|
||||
if hasattr(opt,key):
|
||||
val = getattr(opt,key)
|
||||
if val is not None: # typeset only if opt is set
|
||||
setattr(opt,key,ref_type(val))
|
||||
|
||||
def check_and_set_autoset_opts(): # Raises exception if any check fails
|
||||
|
||||
def nocase_str(key,val,asd):
|
||||
|
|
|
|||
|
|
@ -554,7 +554,6 @@ def init_proto(coin=None,testnet=False,regtest=False,network=None,network_id=Non
|
|||
tokensym = tokensym )
|
||||
|
||||
def init_proto_from_opts():
|
||||
from .opts import opt
|
||||
return init_proto(
|
||||
coin = g.coin,
|
||||
testnet = g.testnet,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class SeedBase(MMGenObject):
|
|||
def __init__(self,seed_bin=None):
|
||||
if not seed_bin:
|
||||
# Truncate random data for smaller seed lengths
|
||||
seed_bin = sha256(get_random(1033)).digest()[:opt.seed_len//8]
|
||||
seed_bin = sha256(get_random(1033)).digest()[:(opt.seed_len or g.dfl_seed_len)//8]
|
||||
elif len(seed_bin)*8 not in g.seed_lens:
|
||||
die(3,'{}: invalid seed length'.format(len(seed_bin)))
|
||||
|
||||
|
|
@ -58,6 +58,7 @@ class SeedBase(MMGenObject):
|
|||
class SubSeedList(MMGenObject):
|
||||
have_short = True
|
||||
nonce_start = 0
|
||||
debug_last_share_sid_len = 3
|
||||
|
||||
def __init__(self,parent_seed):
|
||||
self.member_type = SubSeed
|
||||
|
|
@ -134,7 +135,7 @@ class SubSeedList(MMGenObject):
|
|||
m2 = 'collision with parent Seed ID {},'.format(sid)
|
||||
else:
|
||||
if debug_last_share:
|
||||
sl = g.debug_last_share_sid_len
|
||||
sl = self.debug_last_share_sid_len
|
||||
colliding_idx = [d[:sl] for d in self.data[slen].keys].index(sid[:sl]) + 1
|
||||
sid = sid[:sl]
|
||||
else:
|
||||
|
|
@ -285,7 +286,7 @@ class SeedShareList(SubSeedList):
|
|||
def last_share_debug(last_share):
|
||||
if not debug_last_share:
|
||||
return False
|
||||
sid_len = g.debug_last_share_sid_len
|
||||
sid_len = self.debug_last_share_sid_len
|
||||
lsid = last_share.sid[:sid_len]
|
||||
psid = parent_seed.sid[:sid_len]
|
||||
ssids = [d[:sid_len] for d in self.data['long'].keys]
|
||||
|
|
|
|||
|
|
@ -269,9 +269,10 @@ class MMGenToolCmdMeta(type):
|
|||
|
||||
class MMGenToolCmds(metaclass=MMGenToolCmdMeta):
|
||||
|
||||
def __init__(self,proto=None):
|
||||
def __init__(self,proto=None,mmtype=None):
|
||||
from .protocol import init_proto_from_opts
|
||||
self.proto = proto or init_proto_from_opts()
|
||||
self.mmtype = mmtype or getattr(opt,'type',None) or self.proto.dfl_mmtype
|
||||
if g.token:
|
||||
self.proto.tokensym = g.token.upper()
|
||||
|
||||
|
|
@ -279,7 +280,7 @@ class MMGenToolCmds(metaclass=MMGenToolCmdMeta):
|
|||
global at,kg,ag
|
||||
at = MMGenAddrType(
|
||||
proto = self.proto,
|
||||
id_str = getattr(opt,'type',None) or self.proto.dfl_mmtype )
|
||||
id_str = self.mmtype )
|
||||
if arg != 'at':
|
||||
kg = KeyGenerator(self.proto,at)
|
||||
ag = AddrGenerator(self.proto,at)
|
||||
|
|
@ -460,7 +461,7 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def wif2redeem_script(self,wifkey:'sstr'): # new
|
||||
"convert a WIF private key to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert opt.type == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
self.init_generators()
|
||||
privhex = PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -469,7 +470,7 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def wif2segwit_pair(self,wifkey:'sstr'):
|
||||
"generate both a Segwit P2SH-P2WPKH redeem script and address from WIF"
|
||||
assert opt.type == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
self.init_generators()
|
||||
pubhex = kg.to_pubhex(PrivKey(
|
||||
self.proto,
|
||||
|
|
@ -495,26 +496,26 @@ class MMGenToolCmdCoin(MMGenToolCmds):
|
|||
|
||||
def pubhex2addr(self,pubkeyhex:'sstr'):
|
||||
"convert a hex pubkey to an address"
|
||||
if opt.type == 'segwit':
|
||||
if self.mmtype == 'segwit':
|
||||
return self.proto.pubhex2segwitaddr(pubkeyhex)
|
||||
else:
|
||||
return self.pubhash2addr(hash160(pubkeyhex))
|
||||
|
||||
def pubhex2redeem_script(self,pubkeyhex:'sstr'): # new
|
||||
"convert a hex pubkey to a Segwit P2SH-P2WPKH redeem script"
|
||||
assert opt.type == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
return self.proto.pubhex2redeem_script(pubkeyhex)
|
||||
|
||||
def redeem_script2addr(self,redeem_scripthex:'sstr'): # new
|
||||
"convert a Segwit P2SH-P2WPKH redeem script to an address"
|
||||
assert opt.type == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert self.mmtype == 'segwit','This command is meaningful only for --type=segwit'
|
||||
assert redeem_scripthex[:4] == '0014','{!r}: invalid redeem script'.format(redeem_scripthex)
|
||||
assert len(redeem_scripthex) == 44,'{} bytes: invalid redeem script length'.format(len(redeem_scripthex)//2)
|
||||
return self.pubhash2addr(hash160(redeem_scripthex))
|
||||
|
||||
def pubhash2addr(self,pubhashhex:'sstr'):
|
||||
"convert public key hash to address"
|
||||
if opt.type == 'bech32':
|
||||
if self.mmtype == 'bech32':
|
||||
return self.proto.pubhash2bech32addr(pubhashhex)
|
||||
else:
|
||||
self.init_generators('at')
|
||||
|
|
@ -1108,7 +1109,7 @@ class MMGenToolCmdMonero(MMGenToolCmds):
|
|||
return True
|
||||
|
||||
async def process_wallets(op):
|
||||
opt.accept_defaults = opt.accept_defaults or op.accept_defaults
|
||||
g.accept_defaults = g.accept_defaults or op.accept_defaults
|
||||
from .protocol import init_proto
|
||||
proto = init_proto('xmr',network='mainnet')
|
||||
from .addr import AddrList
|
||||
|
|
@ -1223,8 +1224,7 @@ class tool_api(
|
|||
super().__init__()
|
||||
if not hasattr(opt,'version'):
|
||||
opts.init()
|
||||
opt.use_old_ed25519 = None
|
||||
opt.type = None
|
||||
self.mmtype = self.proto.dfl_mmtype
|
||||
|
||||
def init_coin(self,coinsym,network):
|
||||
"""
|
||||
|
|
@ -1277,11 +1277,11 @@ class tool_api(
|
|||
@property
|
||||
def addrtype(self):
|
||||
"""The currently configured address type (is assignable)"""
|
||||
return opt.type
|
||||
return self.mmtype
|
||||
|
||||
@addrtype.setter
|
||||
def addrtype(self,val):
|
||||
opt.type = val
|
||||
self.mmtype = val
|
||||
|
||||
@property
|
||||
def usr_randchars(self):
|
||||
|
|
|
|||
|
|
@ -801,7 +801,7 @@ class TrackingWallet(MMGenObject,metaclass=aInitMeta):
|
|||
def get_cached_balance(self,addr,session_cache,data_root):
|
||||
if addr in session_cache:
|
||||
return self.proto.coin_amt(session_cache[addr])
|
||||
if not g.use_cached_balances:
|
||||
if not g.cached_balances:
|
||||
return None
|
||||
if addr in data_root and 'balance' in data_root[addr]:
|
||||
return self.proto.coin_amt(data_root[addr]['balance'])
|
||||
|
|
|
|||
|
|
@ -505,27 +505,6 @@ def get_seed_file(cmd_args,nargs,invoked_as=None):
|
|||
|
||||
return cmd_args[0] if cmd_args else (wf,None)[wd_from_opt]
|
||||
|
||||
def get_new_passphrase(desc,passchg=False):
|
||||
|
||||
w = '{}passphrase for {}'.format(('','new ')[bool(passchg)], desc)
|
||||
if opt.passwd_file:
|
||||
pw = ' '.join(get_words_from_file(opt.passwd_file,w))
|
||||
elif opt.echo_passphrase:
|
||||
pw = ' '.join(get_words_from_user('Enter {}: '.format(w)))
|
||||
else:
|
||||
for i in range(g.passwd_max_tries):
|
||||
pw = ' '.join(get_words_from_user('Enter {}: '.format(w)))
|
||||
pw2 = ' '.join(get_words_from_user('Repeat passphrase: '))
|
||||
dmsg('Passphrases: [{}] [{}]'.format(pw,pw2))
|
||||
if pw == pw2:
|
||||
vmsg('Passphrases match'); break
|
||||
else: msg('Passphrases do not match. Try again.')
|
||||
else:
|
||||
die(2,'User failed to duplicate passphrase in {} attempts'.format(g.passwd_max_tries))
|
||||
|
||||
if pw == '': qmsg('WARNING: Empty passphrase')
|
||||
return pw
|
||||
|
||||
def confirm_or_raise(message,q,expect='YES',exit_msg='Exiting at user request'):
|
||||
m = message.strip()
|
||||
if m: msg(m)
|
||||
|
|
@ -701,20 +680,14 @@ def get_data_from_file(infile,desc='data',dash=False,silent=False,binary=False,q
|
|||
|
||||
return data
|
||||
|
||||
def pwfile_reuse_warning():
|
||||
if 'passwd_file_used' in globals():
|
||||
qmsg("Reusing passphrase from file '{}' at user request".format(opt.passwd_file))
|
||||
return True
|
||||
globals()['passwd_file_used'] = True
|
||||
return False
|
||||
passwd_files_used = {}
|
||||
|
||||
def get_mmgen_passphrase(desc,passchg=False):
|
||||
prompt ='Enter {}passphrase for {}: '.format(('','old ')[bool(passchg)],desc)
|
||||
if opt.passwd_file:
|
||||
pwfile_reuse_warning()
|
||||
return ' '.join(get_words_from_file(opt.passwd_file,'passphrase'))
|
||||
else:
|
||||
return ' '.join(get_words_from_user(prompt))
|
||||
def pwfile_reuse_warning(passwd_file):
|
||||
if passwd_file in passwd_files_used:
|
||||
qmsg(f'Reusing passphrase from file {passwd_file!r} at user request')
|
||||
return True
|
||||
passwd_files_used[passwd_file] = True
|
||||
return False
|
||||
|
||||
def my_raw_input(prompt,echo=True,insert_txt='',use_readline=True):
|
||||
|
||||
|
|
@ -760,7 +733,7 @@ def keypress_confirm(prompt,default_yes=False,verbose=False,no_nl=False,complete
|
|||
p = prompt if complete_prompt else '{} {}: '.format(prompt,q)
|
||||
nl = ('\n','\r{}\r'.format(' '*len(p)))[no_nl]
|
||||
|
||||
if opt.accept_defaults:
|
||||
if g.accept_defaults:
|
||||
msg(p)
|
||||
return default_yes
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ from .baseconv import *
|
|||
from .seed import Seed
|
||||
|
||||
def check_usr_seed_len(seed_len):
|
||||
if opt.seed_len != seed_len and 'seed_len' in opt.set_by_user:
|
||||
if opt.seed_len and opt.seed_len != seed_len:
|
||||
die(1,f"ERROR: requested seed length ({opt.seed_len}) doesn't match seed length of source ({seed_len})")
|
||||
|
||||
def _is_mnemonic(s,fmt):
|
||||
oq_save = opt.quiet
|
||||
oq_save = bool(opt.quiet)
|
||||
opt.quiet = True
|
||||
try:
|
||||
Wallet(in_data=s,in_fmt=fmt)
|
||||
|
|
@ -311,7 +311,7 @@ an empty passphrase, just hit ENTER twice.
|
|||
if opt.keep_hash_preset:
|
||||
qmsg(f'Reusing hash preset {old_hp!r} at user request')
|
||||
self.ssdata.hash_preset = old_hp
|
||||
elif 'hash_preset' in opt.set_by_user:
|
||||
elif opt.hash_preset:
|
||||
hp = self.ssdata.hash_preset = opt.hash_preset
|
||||
qmsg(f'Using hash preset {opt.hash_preset!r} requested on command line')
|
||||
else: # Prompt, using old value as default
|
||||
|
|
@ -320,11 +320,11 @@ an empty passphrase, just hit ENTER twice.
|
|||
if (not opt.keep_hash_preset) and self.op == 'pwchg_new':
|
||||
m = (f'changed to {hp!r}','unchanged')[hp==old_hp]
|
||||
qmsg(f'Hash preset {m}')
|
||||
elif 'hash_preset' in opt.set_by_user:
|
||||
elif opt.hash_preset:
|
||||
self.ssdata.hash_preset = opt.hash_preset
|
||||
qmsg(f'Using hash preset {opt.hash_preset!r} requested on command line')
|
||||
else:
|
||||
self._get_hash_preset_from_user(opt.hash_preset,desc_suf)
|
||||
self._get_hash_preset_from_user(g.dfl_hash_preset,desc_suf)
|
||||
|
||||
def _get_new_passphrase(self):
|
||||
desc = '{}passphrase for {}{}'.format(
|
||||
|
|
@ -816,10 +816,8 @@ class MMGenWallet(WalletEnc):
|
|||
|
||||
d.hash_preset = hp = hpdata[0][:-1] # a string!
|
||||
qmsg("Hash preset of wallet: '{}'".format(hp))
|
||||
if 'hash_preset' in opt.set_by_user:
|
||||
uhp = opt.hash_preset
|
||||
if uhp != hp:
|
||||
qmsg("Warning: ignoring user-requested hash preset '{}'".format(uhp))
|
||||
if opt.hash_preset and opt.hash_preset != hp:
|
||||
qmsg('Warning: ignoring user-requested hash preset {opt.hash_preset}')
|
||||
|
||||
hash_params = list(map(int,hpdata[1:]))
|
||||
|
||||
|
|
@ -899,11 +897,11 @@ class Brainwallet(WalletEnc):
|
|||
"""
|
||||
bw_seed_len,d.hash_preset = self.get_bw_params()
|
||||
else:
|
||||
if 'seed_len' not in opt.set_by_user:
|
||||
qmsg(f'Using default seed length of {yellow(str(opt.seed_len))} bits\n'
|
||||
if not opt.seed_len:
|
||||
qmsg(f'Using default seed length of {yellow(str(g.dfl_seed_len))} bits\n'
|
||||
+ 'If this is not what you want, use the --seed-len option' )
|
||||
self._get_hash_preset()
|
||||
bw_seed_len = opt.seed_len
|
||||
bw_seed_len = opt.seed_len or g.dfl_seed_len
|
||||
qmsg_r('Hashing brainwallet data. Please wait...')
|
||||
# Use buflen arg of scrypt.hash() to get seed of desired length
|
||||
seed = scrypt_hash_passphrase(
|
||||
|
|
@ -954,7 +952,7 @@ to exit and re-run the program with the '--old-incog-fmt' option.
|
|||
def _incog_data_size_chk(self):
|
||||
# valid sizes: 56, 64, 72
|
||||
dlen = len(self.fmt_data)
|
||||
seed_len = opt.seed_len
|
||||
seed_len = opt.seed_len or g.dfl_seed_len
|
||||
valid_dlen = self._get_incog_data_len(seed_len)
|
||||
if dlen == valid_dlen:
|
||||
return True
|
||||
|
|
@ -1139,7 +1137,7 @@ harder to find, you're advised to choose a much larger file size than this.
|
|||
qmsg("Getting hidden incog data from file '{}'".format(self.infile.name))
|
||||
|
||||
# Already sanity-checked:
|
||||
d.target_data_len = self._get_incog_data_len(opt.seed_len)
|
||||
d.target_data_len = self._get_incog_data_len(opt.seed_len or g.dfl_seed_len)
|
||||
self._check_valid_offset(self.infile,'read')
|
||||
|
||||
flgs = os.O_RDONLY|os.O_BINARY if g.platform == 'win' else os.O_RDONLY
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -100,6 +100,7 @@ setup(
|
|||
'mmgen.addr',
|
||||
'mmgen.altcoin',
|
||||
'mmgen.baseconv',
|
||||
'mmgen.base_obj',
|
||||
'mmgen.bech32',
|
||||
'mmgen.bip39',
|
||||
'mmgen.cfg',
|
||||
|
|
|
|||
|
|
@ -93,11 +93,6 @@ sample_text_hexdump = (
|
|||
'000040: 6261 6e6b 73').format(n=NL)
|
||||
|
||||
kafile_opts = ['-p1','-Ptest/ref/keyaddrfile_password']
|
||||
kafile_code = (
|
||||
"\nopt.hash_preset = '1'" +
|
||||
"\nopt.set_by_user = ['hash_preset']" +
|
||||
"\nopt.use_old_ed25519 = None" +
|
||||
"\nopt.passwd_file = 'test/ref/keyaddrfile_password'" )
|
||||
|
||||
from test.unit_tests_d.ut_bip39 import unit_test as bip39
|
||||
tests = {
|
||||
|
|
@ -418,11 +413,11 @@ tests = {
|
|||
'pubhash2addr': {
|
||||
'btc_mainnet': [
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5'], '12bYUGXS8SRArZneQDN9YEEYAtEa59Rykm',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['8e34586186551f6320fa3eb2d238a9c61ab8264b'], '3Eevao3DRVXnYym3tdrJDqS3Wc39PQzahn',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['3057f66ddd26fa6ef826b0d5ca067ec3e8f3c178'], 'bc1qxptlvmwaymaxa7pxkr2u5pn7c0508stcncv7ms',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
},
|
||||
'addr2scriptpubkey': {
|
||||
|
|
@ -443,32 +438,32 @@ tests = {
|
|||
'btc_mainnet': [
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'5HwzecKMWD82ppJK3qMKpC7ohXXAwcyAN5VgdJ9PLFaAzpBG4sX',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm',
|
||||
['--type=compressed'], 'opt.type="compressed"' ),
|
||||
['--type=compressed'], 'compressed' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
},
|
||||
'privhex2addr': {
|
||||
'btc_mainnet': [
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'1C5VPtgq9xQ6AcTgMAR3J6GDrs72HC4pS1',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'1Kz9fVSUMshzPejpzW9D95kScgA3rY6QxF',
|
||||
['--type=compressed'], 'opt.type="compressed"' ),
|
||||
['--type=compressed'], 'compressed' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'bc1q6pqnfwwakuuejpm9w52ds342f9d5u36v0qnz7c',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
'eth_mainnet': [
|
||||
( ['0000000000000000000000000000000000000000000000000000000000000001'],
|
||||
|
|
@ -501,68 +496,68 @@ tests = {
|
|||
'zec_mainnet': [
|
||||
( ['0000000000000000000000000000000000000000000000000000000000000001'],
|
||||
'zceQDpyNwek7dKqF5ZuFGj7YrNVxh7X1aPkrVxDLVxWSiZAFDEuy5C7XNV8VhyZ3ghTPQ61xjCGiyLT3wqpiN1Yi6mdmaCq',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
|
||||
'zcY1hqJ3P5ifjnWk1BcXpjrLG5XeJZUSPCiiVTF9LXrejxBzAsFWcNyr6PudwQHm8DnQpD8HEaM3dh8sB6cf91ciAa53YQ1',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'],
|
||||
'zcY1hqJ3P5ifjnWk1BcXpjrLG5XeJZUSPCiiVTF9LXrejxBzAsFWcNyr6PudwQHm8DnQpD8HEaM3dh8sB6cf91ciAa53YQ1',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['00000000000000000000000000000000000000000000000000000000000000ff'],
|
||||
'zcck12KgVY34LJwVEDLN8sXhL787zmjKqPsP1uBYRHs75bL9sQu4P7wcc5ZJTjKsL376zaSpsYqGxK94JbiYcNoH8DkeGbN',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0f'],
|
||||
'zcJ9hEezG1Jeye5dciqiMDh6SXtYbUsircGmpVyhHWyzyxDVRRDs5Q8M7hG3c7nDcvd5Pw4u4wV9RAQmq5RCBZq5wVyMQV8',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'],
|
||||
'zchFELwBxqsAubsLQ8yZgPCDDGukjXJssgCbiTPwFNmFwn9haLnDatzfhLdZzJT4PcU4o2yr92B52UFirUzEdF6ZYM2gBkM',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
],
|
||||
},
|
||||
'privhex2pubhex': {
|
||||
'btc_mainnet': [
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'044281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e972757f3254c322eeaa3cb6bf97cc5ecf8d4387b0df2c0b1e6ee18fe3a6977a7d57a',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727',
|
||||
['--type=compressed'], 'opt.type="compressed"' ),
|
||||
['--type=compressed'], 'compressed' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492'],
|
||||
'024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
},
|
||||
'pubhex2addr': {
|
||||
'btc_mainnet': [
|
||||
( ['044281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e972757f3254c322eeaa3cb6bf97cc5ecf8d4387b0df2c0b1e6ee18fe3a6977a7d57a'],
|
||||
'1C5VPtgq9xQ6AcTgMAR3J6GDrs72HC4pS1',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727'],
|
||||
'1Kz9fVSUMshzPejpzW9D95kScgA3rY6QxF',
|
||||
['--type=compressed'], 'opt.type="compressed"' ),
|
||||
['--type=compressed'], 'compressed' ),
|
||||
( ['024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727'],
|
||||
'3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727'],
|
||||
'bc1q6pqnfwwakuuejpm9w52ds342f9d5u36v0qnz7c',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
},
|
||||
'pubhex2redeem_script': {
|
||||
'btc_mainnet': [
|
||||
( ['024281a85c9ce87279e028410b851410d65136304cfbbbeaaa8e2e3931cf4e9727'],
|
||||
'0014d04134b9ddb7399907657514d846aa495b4e474c',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
],
|
||||
},
|
||||
'redeem_script2addr': {
|
||||
'btc_mainnet': [
|
||||
( ['0014d04134b9ddb7399907657514d846aa495b4e474c'],
|
||||
'3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
],
|
||||
},
|
||||
'randpair': {
|
||||
|
|
@ -576,13 +571,13 @@ tests = {
|
|||
'wif2addr': {
|
||||
'btc_mainnet': [
|
||||
( ['5HwzecKMWD82ppJK3qMKpC7ohXXAwcyAN5VgdJ9PLFaAzpBG4sX'],
|
||||
'1C5VPtgq9xQ6AcTgMAR3J6GDrs72HC4pS1', ['--type=legacy'], 'opt.type="legacy"' ),
|
||||
'1C5VPtgq9xQ6AcTgMAR3J6GDrs72HC4pS1', ['--type=legacy'], 'legacy' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'1Kz9fVSUMshzPejpzW9D95kScgA3rY6QxF', ['--type=compressed'], 'opt.type="compressed"' ),
|
||||
'1Kz9fVSUMshzPejpzW9D95kScgA3rY6QxF', ['--type=compressed'], 'compressed' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg', ['--type=segwit'], 'opt.type="segwit"' ),
|
||||
'3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg', ['--type=segwit'], 'segwit' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'bc1q6pqnfwwakuuejpm9w52ds342f9d5u36v0qnz7c', ['--type=bech32'], 'opt.type="bech32"' ),
|
||||
'bc1q6pqnfwwakuuejpm9w52ds342f9d5u36v0qnz7c', ['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
'eth_mainnet': [
|
||||
( ['0000000000000000000000000000000000000000000000000000000000000001'],
|
||||
|
|
@ -615,52 +610,52 @@ tests = {
|
|||
'zec_mainnet': [
|
||||
( ['SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56FjqVUYR'],
|
||||
'zceQDpyNwek7dKqF5ZuFGj7YrNVxh7X1aPkrVxDLVxWSiZAFDEuy5C7XNV8VhyZ3ghTPQ61xjCGiyLT3wqpiN1Yi6mdmaCq',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['SKxv1peuQvMT4TvqPLqKy1px3oqLm98Evi948VU8N8VKcf7C2umc'],
|
||||
'zcY1hqJ3P5ifjnWk1BcXpjrLG5XeJZUSPCiiVTF9LXrejxBzAsFWcNyr6PudwQHm8DnQpD8HEaM3dh8sB6cf91ciAa53YQ1',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['SKxv1peuQvMT4TvqPLqKy1px3oqLm98Evi948VU8N8VKcf7C2umc'],
|
||||
'zcY1hqJ3P5ifjnWk1BcXpjrLG5XeJZUSPCiiVTF9LXrejxBzAsFWcNyr6PudwQHm8DnQpD8HEaM3dh8sB6cf91ciAa53YQ1',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56kQw4qjm'],
|
||||
'zcck12KgVY34LJwVEDLN8sXhL787zmjKqPsP1uBYRHs75bL9sQu4P7wcc5ZJTjKsL376zaSpsYqGxK94JbiYcNoH8DkeGbN',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['SKxv1peuQvMT4TvqPLqKy1px3oqLm98Evi948VU8N8VKcBwrLwiu'],
|
||||
'zcJ9hEezG1Jeye5dciqiMDh6SXtYbUsircGmpVyhHWyzyxDVRRDs5Q8M7hG3c7nDcvd5Pw4u4wV9RAQmq5RCBZq5wVyMQV8',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
( ['SKxuS56e99jpCeD9mMQ5o63zoGPakNdM9HCvt4Vt2cypvRjCdvGJ'],
|
||||
'zchFELwBxqsAubsLQ8yZgPCDDGukjXJssgCbiTPwFNmFwn9haLnDatzfhLdZzJT4PcU4o2yr92B52UFirUzEdF6ZYM2gBkM',
|
||||
['--type=zcash_z'], 'opt.type="zcash_z"' ),
|
||||
['--type=zcash_z'], 'zcash_z' ),
|
||||
],
|
||||
},
|
||||
'wif2hex': {
|
||||
'btc_mainnet': [
|
||||
( ['5HwzecKMWD82ppJK3qMKpC7ohXXAwcyAN5VgdJ9PLFaAzpBG4sX'],
|
||||
'118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492',
|
||||
None, 'opt.type="legacy"' ),
|
||||
None, 'legacy' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492',
|
||||
['--type=compressed'], 'opt.type="compressed"' ),
|
||||
['--type=compressed'], 'compressed' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'118089d66b4a5853765e94923abdd5de4616c6e5118089d66b4a5853765e9492',
|
||||
['--type=bech32'], 'opt.type="bech32"' ),
|
||||
['--type=bech32'], 'bech32' ),
|
||||
],
|
||||
},
|
||||
'wif2redeem_script': {
|
||||
'btc_mainnet': [
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
'0014d04134b9ddb7399907657514d846aa495b4e474c',
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
],
|
||||
},
|
||||
'wif2segwit_pair': {
|
||||
'btc_mainnet': [
|
||||
( ['KwojSzt1VvW343mQfWQi3J537siAt5ktL2qbuCg1ZyKR8BLQ6UJm'],
|
||||
('0014d04134b9ddb7399907657514d846aa495b4e474c','3AhjTiWHhVJAi1s5CfKMcLzYps12x3gZhg'),
|
||||
['--type=segwit'], 'opt.type="segwit"' ),
|
||||
['--type=segwit'], 'segwit' ),
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
@ -720,43 +715,43 @@ tests = {
|
|||
'keyaddrfile_chksum': {
|
||||
'btc_mainnet': [
|
||||
( ['test/ref/98831F3A[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'9F2D D781 1812 8BAD', kafile_opts, kafile_code ),
|
||||
'9F2D D781 1812 8BAD', kafile_opts ),
|
||||
],
|
||||
'btc_testnet': [
|
||||
( ['test/ref/98831F3A[1,31-33,500-501,1010-1011].testnet.akeys.mmenc'],
|
||||
'88CC 5120 9A91 22C2', kafile_opts, kafile_code ),
|
||||
'88CC 5120 9A91 22C2', kafile_opts ),
|
||||
],
|
||||
'ltc_mainnet': [
|
||||
( ['test/ref/litecoin/98831F3A-LTC[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'B804 978A 8796 3ED4', kafile_opts, kafile_code ),
|
||||
'B804 978A 8796 3ED4', kafile_opts ),
|
||||
],
|
||||
'ltc_testnet': [
|
||||
( ['test/ref/litecoin/98831F3A-LTC[1,31-33,500-501,1010-1011].testnet.akeys.mmenc'],
|
||||
'98B5 AC35 F334 0398', kafile_opts, kafile_code ),
|
||||
'98B5 AC35 F334 0398', kafile_opts ),
|
||||
],
|
||||
'zec_mainnet': [
|
||||
( ['test/ref/zcash/98831F3A-ZEC-C[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'F05A 5A5C 0C8E 2617', kafile_opts, kafile_code ),
|
||||
'F05A 5A5C 0C8E 2617', kafile_opts ),
|
||||
( ['test/ref/zcash/98831F3A-ZEC-Z[1,31-33,500-501,1010-1011].akeys.mmenc'], '6B87 9B2D 0D8D 8D1E',
|
||||
kafile_opts + ['--type=zcash_z'], kafile_code + '\nopt.type = "zcash_z"' ),
|
||||
kafile_opts + ['--type=zcash_z'], 'opt.type = "zcash_z"' ),
|
||||
],
|
||||
'xmr_mainnet': [
|
||||
( ['test/ref/monero/98831F3A-XMR-M[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'E0D7 9612 3D67 404A', kafile_opts, kafile_code ), ],
|
||||
'E0D7 9612 3D67 404A', kafile_opts ), ],
|
||||
'dash_mainnet': [
|
||||
( ['test/ref/dash/98831F3A-DASH-C[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'E83D 2C63 FEA2 4142', kafile_opts, kafile_code ), ],
|
||||
'E83D 2C63 FEA2 4142', kafile_opts ), ],
|
||||
'eth_mainnet': [
|
||||
( ['test/ref/ethereum/98831F3A-ETH[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'E400 70D9 0AE3 C7C2', kafile_opts, kafile_code ), ],
|
||||
'E400 70D9 0AE3 C7C2', kafile_opts ), ],
|
||||
'etc_mainnet': [
|
||||
( ['test/ref/ethereum_classic/98831F3A-ETC[1,31-33,500-501,1010-1011].akeys.mmenc'],
|
||||
'EF49 967D BD6C FE45', kafile_opts, kafile_code ), ],
|
||||
'EF49 967D BD6C FE45', kafile_opts ), ],
|
||||
},
|
||||
'passwdfile_chksum': {
|
||||
'btc_mainnet': [
|
||||
( ['test/ref/98831F3A-фубар@crypto.org-b58-20[1,4,1100].pws'],
|
||||
'DDD9 44B0 CA28 183F', kafile_opts, kafile_code ), ],
|
||||
'DDD9 44B0 CA28 183F', kafile_opts ), ],
|
||||
},
|
||||
'txview': {
|
||||
'btc_mainnet': [ ( ['test/ref/0B8D5A[15.31789,14,tl=1320969600].rawtx'], None ), ],
|
||||
|
|
@ -801,7 +796,7 @@ async def run_test(gid,cmd_name):
|
|||
|
||||
msg_r(green(m)+'\n' if opt.verbose else m)
|
||||
|
||||
def fork_cmd(cmd_name,args,out,opts,exec_code):
|
||||
def fork_cmd(cmd_name,args,out,opts):
|
||||
cmd = list(tool_cmd) + (opts or []) + [cmd_name] + args
|
||||
vmsg('{} {}'.format(green('Executing'),cyan(' '.join(cmd))))
|
||||
cp = run(cmd,input=stdin_input or None,stdout=PIPE,stderr=PIPE)
|
||||
|
|
@ -819,13 +814,16 @@ async def run_test(gid,cmd_name):
|
|||
|
||||
return cmd_out.strip()
|
||||
|
||||
async def run_func(cmd_name,args,out,opts,exec_code):
|
||||
async def run_func(cmd_name,args,out,opts,mmtype):
|
||||
vmsg('{}: {}{}'.format(purple('Running'),
|
||||
' '.join([cmd_name]+[repr(e) for e in args]),
|
||||
' '+exec_code if exec_code else '' ))
|
||||
if exec_code: exec(exec_code)
|
||||
' '+mmtype if mmtype else '' ))
|
||||
aargs,kwargs = tool._process_args(cmd_name,args)
|
||||
oq_save = opt.quiet
|
||||
tm = tool.MMGenToolCmdMeta
|
||||
cls_name = tm.classname(tm,cmd_name)
|
||||
tobj = getattr(tool,cls_name)(mmtype=mmtype)
|
||||
method = getattr(tobj,cmd_name)
|
||||
oq_save = bool(opt.quiet)
|
||||
if not opt.verbose:
|
||||
opt.quiet = True
|
||||
if stdin_input:
|
||||
|
|
@ -834,7 +832,7 @@ async def run_test(gid,cmd_name):
|
|||
os.close(fd1)
|
||||
stdin_save = os.dup(0)
|
||||
os.dup2(fd0,0)
|
||||
cmd_out = tc.call(cmd_name,*aargs,**kwargs)
|
||||
cmd_out = method(*aargs,**kwargs)
|
||||
os.dup2(stdin_save,0)
|
||||
os.wait()
|
||||
opt.quiet = oq_save
|
||||
|
|
@ -845,13 +843,13 @@ async def run_test(gid,cmd_name):
|
|||
vmsg('Input: {!r}'.format(stdin_input))
|
||||
sys.exit(0)
|
||||
else:
|
||||
ret = tc.call(cmd_name,*aargs,**kwargs)
|
||||
ret = method(*aargs,**kwargs)
|
||||
if type(ret).__name__ == 'coroutine':
|
||||
ret = await ret
|
||||
opt.quiet = oq_save
|
||||
return ret
|
||||
|
||||
def tool_api(cmd_name,args,out,opts,exec_code):
|
||||
def tool_api(cmd_name,args,out,opts):
|
||||
from mmgen.tool import tool_api
|
||||
tool = tool_api()
|
||||
if opts:
|
||||
|
|
@ -868,7 +866,7 @@ async def run_test(gid,cmd_name):
|
|||
return getattr(tool,cmd_name)(*pargs,**kwargs)
|
||||
|
||||
for d in data:
|
||||
args,out,opts,exec_code = d + tuple([None] * (4-len(d)))
|
||||
args,out,opts,mmtype = d + tuple([None] * (4-len(d)))
|
||||
stdin_input = None
|
||||
if args and type(args[0]) == bytes:
|
||||
stdin_input = args[0]
|
||||
|
|
@ -877,14 +875,14 @@ async def run_test(gid,cmd_name):
|
|||
if opt.tool_api:
|
||||
if args and args[0 ]== '-':
|
||||
continue
|
||||
cmd_out = tool_api(cmd_name,args,out,opts,exec_code)
|
||||
cmd_out = tool_api(cmd_name,args,out,opts)
|
||||
elif opt.fork:
|
||||
cmd_out = fork_cmd(cmd_name,args,out,opts,exec_code)
|
||||
cmd_out = fork_cmd(cmd_name,args,out,opts)
|
||||
else:
|
||||
if stdin_input and g.platform == 'win':
|
||||
msg('Skipping for MSWin - no os.fork()')
|
||||
continue
|
||||
cmd_out = await run_func(cmd_name,args,out,opts,exec_code)
|
||||
cmd_out = await run_func(cmd_name,args,out,opts,mmtype)
|
||||
|
||||
try: vmsg('Output:\n{}\n'.format(cmd_out))
|
||||
except: vmsg('Output:\n{}\n'.format(repr(cmd_out)))
|
||||
|
|
@ -967,7 +965,14 @@ def list_tested_cmds():
|
|||
|
||||
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]
|
||||
|
||||
cmd_args = opts.init(opts_data,add_opts=['use_old_ed25519'])
|
||||
cmd_args = opts.init(
|
||||
opts_data,
|
||||
add_opts = ['use_old_ed25519'],
|
||||
init_opts = {
|
||||
'usr_randchars': 0,
|
||||
'hash_preset': '1',
|
||||
'passwd_file': 'test/ref/keyaddrfile_password',
|
||||
})
|
||||
|
||||
from mmgen.protocol import init_proto_from_opts
|
||||
proto = init_proto_from_opts()
|
||||
|
|
@ -1014,8 +1019,6 @@ if opt.fork:
|
|||
tool_cmd = ('python3','-m','trace','--count','--coverdir='+d,'--file='+f) + tool_cmd
|
||||
elif g.platform == 'win':
|
||||
tool_cmd = ('python3',) + tool_cmd
|
||||
else:
|
||||
opt.usr_randchars = 0
|
||||
|
||||
start_time = int(time.time())
|
||||
|
||||
|
|
|
|||
103
test/unit_tests_d/ut_lockable.py
Executable file
103
test/unit_tests_d/ut_lockable.py
Executable file
|
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
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):
|
||||
|
||||
def run_test(self,name,ut):
|
||||
|
||||
from mmgen.base_obj import AttrCtrl,Lockable
|
||||
|
||||
qmsg_r('Testing class AttrCtrl...')
|
||||
|
||||
class MyAttrCtrl(AttrCtrl):
|
||||
foo = 'fooval'
|
||||
ac = MyAttrCtrl()
|
||||
ac.lock()
|
||||
|
||||
ac.foo = 'new fooval'
|
||||
ac.foo = 'new fooval2'
|
||||
|
||||
class MyAttrCtrlClsCheck(AttrCtrl):
|
||||
_use_class_attr = True
|
||||
foo = 'fooval'
|
||||
bar = None
|
||||
acc = MyAttrCtrlClsCheck()
|
||||
acc.lock()
|
||||
|
||||
acc.foo = 'new_fooval'
|
||||
acc.foo = 'new_fooval2'
|
||||
acc.bar = 'bar val'
|
||||
acc.bar = 1 # class attribute bar is None, so can be set to any type
|
||||
|
||||
qmsg('OK')
|
||||
qmsg_r('Testing class Lockable...')
|
||||
|
||||
class MyLockable(Lockable): # class has no attrs, like UserOpts
|
||||
_set_ok = ('foo','baz')
|
||||
_reset_ok = ('bar','baz')
|
||||
|
||||
lc = MyLockable()
|
||||
lc.foo = None
|
||||
lc.bar = 'barval'
|
||||
lc.baz = 1
|
||||
lc.qux = 1
|
||||
lc.lock()
|
||||
|
||||
lc.foo = 'fooval2'
|
||||
lc.bar = 'barval2'
|
||||
lc.bar = 'barval3'
|
||||
lc.baz = 2
|
||||
lc.baz = 3
|
||||
|
||||
class MyLockableClsCheck(Lockable): # class has attrs, like GlobalContext
|
||||
_use_class_attr = True
|
||||
_set_ok = ('foo','baz')
|
||||
_reset_ok = ('bar','baz')
|
||||
foo = None
|
||||
bar = 1
|
||||
baz = 3.5
|
||||
qux = 'quxval'
|
||||
|
||||
lcc = MyLockableClsCheck()
|
||||
lcc.lock()
|
||||
|
||||
lcc.foo = 'fooval2' # class attribute foo is None, so can be set to any type
|
||||
lcc.bar = 2
|
||||
lcc.bar = 3 # bar is in reset list
|
||||
lcc.baz = 3.2
|
||||
lcc.baz = 3.1 # baz is in both lists
|
||||
qmsg('OK')
|
||||
|
||||
qmsg('Checking error handling:')
|
||||
|
||||
def bad1(): ac.x = 1
|
||||
def bad2(): acc.foo = 1
|
||||
def bad3(): lc.foo = 'fooval3'
|
||||
def bad4(): lc.baz = 'str'
|
||||
def bad5(): lcc.bar = 'str'
|
||||
def bad6(): lc.qux = 2
|
||||
def bad7(): lcc.qux = 'quxval2'
|
||||
def bad8(): lcc.foo = 'fooval3'
|
||||
def bad9(): lc.x = 1
|
||||
def bad10(): lcc.x = 1
|
||||
|
||||
ut.process_bad_data((
|
||||
('attr (1)', 'AttributeError', 'has no attr', bad1 ),
|
||||
('attr (2)', 'AttributeError', 'has no attr', bad9 ),
|
||||
('attr (3)', 'AttributeError', 'has no attr', bad10 ),
|
||||
('attr type (1)', 'AttributeError', 'type', bad2 ),
|
||||
("attr type (2)", 'AttributeError', 'type', bad4 ),
|
||||
("attr type (3)", 'AttributeError', 'type', bad5 ),
|
||||
("attr (can't set)", 'AttributeError', 'read-only', bad6 ),
|
||||
("attr (can't set)", 'AttributeError', 'read-only', bad7 ),
|
||||
("attr (can't reset)", 'AttributeError', 'reset', bad3 ),
|
||||
("attr (can't reset)", 'AttributeError', 'reset', bad8 ),
|
||||
))
|
||||
|
||||
qmsg('OK')
|
||||
return True
|
||||
|
|
@ -149,7 +149,6 @@ class unit_test(object):
|
|||
seed = Seed(seed_bin)
|
||||
ssm_save = SeedShareIdx.max_val
|
||||
ssm = SeedShareIdx.max_val = 2048
|
||||
g.debug_last_share_sid_len = 3
|
||||
shares = SeedShareList(seed,count=ssm,id_str='foo',master_idx=1,debug_last_share=True)
|
||||
lsid = shares.last_share.sid
|
||||
collisions = shares.data['long'][lsid][1]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue