release/testing: UTF8 testing fixes, other fixes and improvements
This commit is contained in:
parent
cd3e1e3574
commit
5fe92460ad
15 changed files with 136 additions and 117 deletions
56
README.md
56
README.md
|
|
@ -1,10 +1,6 @@
|
|||
***Note: This is the source code repository of the MMGen wallet system. For an
|
||||
easier way to install MMGen, check out the prebuilt bootable USB images on the
|
||||
[MMGenLive][8] home page.***
|
||||
|
||||
# MMGen = Multi-Mode GENerator
|
||||
|
||||
##### a Bitcoin and altcoin online/offline software wallet for the command line
|
||||
##### An online/offline cryptocurrency wallet for the command line
|
||||
|
||||
### Description
|
||||
|
||||
|
|
@ -15,7 +11,7 @@ offline computers to provide a robust solution for securely storing, tracking,
|
|||
sending and receiving your crypto assets.
|
||||
|
||||
The online computer is used for tracking balances and creating and sending
|
||||
transactions, while the offline computer (typically an air-gapped, low-power
|
||||
transactions, while the offline machine (typically an air-gapped, low-power
|
||||
device such as a Raspberry Pi) takes care of wallet creation, address generation
|
||||
and transaction signing. All operations involving secret data are handled
|
||||
offline: **your seed and private keys never come into contact with a
|
||||
|
|
@ -34,36 +30,11 @@ of address/key pairs from a single seed. Your wallet never changes, so you need
|
|||
back it up only once.
|
||||
|
||||
At the heart of the MMGen system is the seed, the “master key” providing access
|
||||
to all your crypto assets. The seed can be stored in five different ways:
|
||||
|
||||
1. as a password-encrypted wallet. The crack-resistant Scrypt hash function
|
||||
is used for password hashing. Scrypt’s parameters can be tuned to make
|
||||
your wallet’s password very difficult to crack should it fall into the
|
||||
wrong hands. The wallet is a compact, six-line text file suitable for
|
||||
printing or even writing out by hand;
|
||||
|
||||
2. as a seed file: a one-line, conveniently formatted base-58 representation
|
||||
of your unencrypted seed plus a checksum;
|
||||
|
||||
3. as an Electrum-like mnemonic seed phrase of 12, 18 or 24 words;
|
||||
|
||||
4. as a brainwallet passphrase (this option is recommended only for users who
|
||||
understand the risks of brainwallets and know how to create a strong
|
||||
brainwallet passphrase). The brainwallet is hashed using Scrypt with
|
||||
tunable parameters, making it much harder to crack than standard SHA256
|
||||
brainwallets; or
|
||||
|
||||
5. as “incognito data”, a wallet encrypted to make it indistinguishable
|
||||
from random data. This data can be hidden on a disk partition filled with
|
||||
random data, or in a file at an offset of your choice. This makes it
|
||||
possible to hide a wallet at a non-private location—on cloud storage, for
|
||||
example. Incognito wallet hiding/retrieval is seamlessly integrated into
|
||||
MMGen, making its use nearly as easy as that of the standard wallet.
|
||||
|
||||
The best part is that all these methods can be combined. If you forget your
|
||||
mnemonic seed phrase, for example, you can regenerate it from a stored wallet
|
||||
or seed file. Correspondingly, a lost wallet can be regenerated from a mnemonic
|
||||
or seed or vice-versa.
|
||||
to all your crypto assets. The seed can be stored in many different formats:
|
||||
as a password-encrypted wallet (the default), as a one-line base58 or
|
||||
hexidecimal seed file, as an Electrum-based mnemonic seed phrase, as a
|
||||
brainwallet passphrase, or as “incognito data” hideable within random data in a
|
||||
file or block device. Conversion between all formats is supported.
|
||||
|
||||
***mmgen-txcreate running in a terminal window***
|
||||
![mmgen-txcreate running in a terminal window][9]
|
||||
|
|
@ -94,7 +65,7 @@ the more prosaic 2048-word [BIP39 wordlist][bw] used in most wallets today.
|
|||
[Litecoin][bx], [Ethereum][E], Ethereum Classic and [ERC20 tokens][E].
|
||||
- **[Address generation support][ag]** for the above coins, plus [Monero][mx],
|
||||
[Zcash][zx] (t and z addresses) and [144 Bitcoin-derived altcoins][ax].
|
||||
- **Support for all Bitcoin address types** including segwit-p2sh and bech32.
|
||||
- **Support for all Bitcoin address types** including Segwit-P2SH and Bech32.
|
||||
- **Independent key derivation for each address type:** No two addresses ever
|
||||
share the same private key. Certain wallets in wide use today regrettably
|
||||
fail to guarantee this property, leading to the danger of inadvertent key
|
||||
|
|
@ -118,11 +89,12 @@ the more prosaic 2048-word [BIP39 wordlist][bw] used in most wallets today.
|
|||
always be regenerated from their parent.
|
||||
- **[Transaction autosigning][X]:** This feature puts your offline signing
|
||||
machine into “hands-off” mode, allowing you to transact directly from cold
|
||||
storage securely and conveniently. Additional LED signaling support is
|
||||
storage securely and conveniently. Additional LED blinking support is
|
||||
provided for Raspbian and Armbian platforms.
|
||||
- **[Password generation][G]:** MMGen can be used to generate and manage your
|
||||
online passwords. Passwords are identified by arbitrarily chosen strings like
|
||||
“alice@github” or “bob@reddit”.
|
||||
online passwords. Password lists are identified by arbitrarily chosen strings
|
||||
like “alice@github” or “bob@reddit”. Passwords of different lengths and
|
||||
formats are supported.
|
||||
- **Selectable seed lengths** of 128, 192 or 256 bits. Subwallets may have
|
||||
shorter seeds than their parent.
|
||||
- **User-enhanced entropy:** All operations requiring random data will prompt
|
||||
|
|
@ -145,6 +117,10 @@ the more prosaic 2048-word [BIP39 wordlist][bw] used in most wallets today.
|
|||
you to automate repetitive tasks using shell scripts. Most of the
|
||||
`mmgen-tool` utility’s commands can be piped.
|
||||
|
||||
#### Supported platforms:
|
||||
|
||||
Linux, Armbian, Raspbian, Windows/MSYS2
|
||||
|
||||
### Download/Install
|
||||
|
||||
> #### [Install a prebuilt bootable image (MMGenLive) on a USB stick][8]
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
- XOR seed splitting: 7311f474, 237567bc, c7ca0c3d (see
|
||||
[XOR-Seed-Splitting:-Theory-and-Practice][xo] for additional information)
|
||||
- ETH tracking-wallet balance caching, Parity light client optimizations:
|
||||
d0f8c44b
|
||||
- Full BIP39 mnemonic support: 8519b68b, 8705e57b
|
||||
- Monero new-style mnemonic support: cfa16418
|
||||
- New die-roll wallet format, interactive die-roll entry: c7786369, 4714ef84
|
||||
- New dieroll wallet format, interactive dieroll entry: c7786369, 4714ef84
|
||||
- ETH tracking-wallet balance caching, Parity light client optimizations:
|
||||
d0f8c44b
|
||||
|
||||
#### Other changes/additions/improvements:
|
||||
|
||||
|
|
@ -17,28 +17,26 @@
|
|||
- Monero wallet creation/syncing tool reimplemented, now works under MSYS2:
|
||||
3951925a
|
||||
- New Tool API interface: f8056630
|
||||
- Full automation of test suite, automatic starting/stopping of daemons
|
||||
- Plus lots of code cleanups, bugfixes, and additional tests!
|
||||
- New [Daemon control interface][dc] and [test daemon start/stop utilities][ss]
|
||||
- Full automation of test suite with automatic starting/stopping of daemons
|
||||
- UTF8 password entry works reliably under MSYS2, warnings disabled
|
||||
- Plus lots of code cleanups, bugfixes, new tests and [expanded documentation][w]
|
||||
|
||||
This release has been tested on the following platforms:
|
||||
|
||||
Debian Buster / x86_64
|
||||
Ubuntu Bionic / x86_64 / qemu-x86_64
|
||||
Armbian Bionic / Orange Pi PC2 (armv8)
|
||||
Raspbian Buster / Raspberry Pi B (armv7) (no Parity, no Monerod)
|
||||
Windows 10 Enterprise Eng. / MSYS2 / qemu-x86_64
|
||||
|
||||
and with the following coin daemon versions:
|
||||
|
||||
Bitcoin Core v0.19.0.1
|
||||
Bitcoin-ABC v0.20.9
|
||||
Litecoin Core v0.17.1
|
||||
Monerod v0.15.0.1
|
||||
Parity Ethereum v2.7.2
|
||||
|
||||
Testing TBD on the following platforms:
|
||||
|
||||
Ubuntu Bionic / x86_64 / qemu-x86_64
|
||||
Ubuntu Xenial (+Python 3.6.7) / x86_64
|
||||
Armbian Bionic / Orange Pi PC2 (no Parity or Monerod)
|
||||
Raspbian Stretch / Raspberry Pi B (no Parity or Monerod)
|
||||
Bitcoin Core 0.17.1, 0.19.0.1
|
||||
Bitcoin-ABC 0.21.0
|
||||
Litecoin Core 0.17.1
|
||||
Monerod 0.15.0.1
|
||||
Parity Ethereum 2.7.2
|
||||
|
||||
Altcoin address generation has been additionally tested using the following
|
||||
tools as references:
|
||||
|
|
@ -48,3 +46,6 @@ tools as references:
|
|||
vanitygen-plus 22123128 (https://github.com/exploitagency/vanitygen-plus)
|
||||
|
||||
[xo]: https://github.com/mmgen/mmgen/wiki/XOR-Seed-Splitting:-Theory-and-Practice.md
|
||||
[dc]: https://github.com/mmgen/mmgen/blob/master/mmgen/daemon.py
|
||||
[ss]: https://github.com/mmgen/mmgen/blob/master/test/start-coin-daemons.py
|
||||
[w]: https://github.com/mmgen/mmgen/wiki
|
||||
|
|
|
|||
|
|
@ -158,13 +158,20 @@ class Daemon(MMGenObject):
|
|||
self.stop(silent=silent)
|
||||
return self.start(silent=silent)
|
||||
|
||||
def test_socket(self,host,port,timeout=10):
|
||||
import socket
|
||||
try: socket.create_connection((host,port),timeout=timeout).close()
|
||||
except: return False
|
||||
else: return True
|
||||
|
||||
def wait_for_state(self,req_state):
|
||||
for i in range(200):
|
||||
for i in range(300):
|
||||
if self.state == req_state:
|
||||
return True
|
||||
time.sleep(0.2)
|
||||
else:
|
||||
die(2,'Daemon wait timeout for {} {} exceeded'.format(self.daemon_id.upper(),self.network))
|
||||
m = 'Wait for state {!r} timeout exceeded for daemon {} {}'
|
||||
die(2,m.format(req_state,self.daemon_id.upper(),self.network))
|
||||
|
||||
@classmethod
|
||||
def check_implement(cls):
|
||||
|
|
@ -221,6 +228,8 @@ class MoneroWalletDaemon(Daemon):
|
|||
|
||||
@property
|
||||
def state(self):
|
||||
if not self.test_socket(g.monero_wallet_rpc_host,self.rpc_port):
|
||||
return 'stopped'
|
||||
from mmgen.rpc import MoneroWalletRPCConnection
|
||||
try:
|
||||
MoneroWalletRPCConnection(
|
||||
|
|
@ -291,7 +300,11 @@ class CoinDaemon(Daemon):
|
|||
if network == 'regtest':
|
||||
me.desc = 'regtest daemon'
|
||||
if test_suite:
|
||||
rel_datadir = os.path.join('test','data_dir','regtest',daemon_id)
|
||||
rel_datadir = os.path.join(
|
||||
'test',
|
||||
'data_dir{}'.format('-α' if g.debug_utf8 else ''),
|
||||
'regtest',
|
||||
daemon_id )
|
||||
else:
|
||||
me.datadir = os.path.join(g.data_dir_root,'regtest',daemon_id)
|
||||
elif test_suite:
|
||||
|
|
@ -431,6 +444,8 @@ class MoneroDaemon(CoinDaemon):
|
|||
|
||||
@property
|
||||
def state(self):
|
||||
if not self.test_socket(g.monero_wallet_rpc_host,self.rpc_port):
|
||||
return 'stopped'
|
||||
cp = self.run_cmd(
|
||||
[self.coind_exec]
|
||||
+ self.shared_args
|
||||
|
|
|
|||
|
|
@ -209,9 +209,6 @@ class g(object):
|
|||
max_tx_file_size = 100000
|
||||
max_input_size = 1024 * 1024
|
||||
|
||||
# pexpect chokes on these utf8 chars under MSYS2
|
||||
lq,rq = (('“','”'),('"','"'))[bool(os.getenv('MMGEN_TEST_SUITE')) and platform=='win']
|
||||
|
||||
passwd_max_tries = 5
|
||||
|
||||
max_urandchars = 80
|
||||
|
|
|
|||
|
|
@ -294,10 +294,6 @@ def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
|
|||
if not 'code' in opts_data:
|
||||
opts_data['code'] = {}
|
||||
opts_data['code']['long_options'] = common_opts_data['code']
|
||||
if g.debug_utf8:
|
||||
for k in opts_data:
|
||||
if type(opts_data[k]) == str:
|
||||
opts_data[k] += '-α'
|
||||
mmgen.share.Opts.print_help(opts_data,opt_filter) # exits
|
||||
|
||||
if g.bob or g.alice:
|
||||
|
|
|
|||
|
|
@ -866,12 +866,12 @@ class MMGenMnemonic(SeedSourceUnenc):
|
|||
|
||||
m = 'Enter your {ml}-word seed phrase, hitting ENTER or SPACE after each word.\n'
|
||||
m += "Optionally, you may use pad characters. Anything you type that's not a\n"
|
||||
m += 'lowercase letter will be treated as a {lq}pad character{rq}, i.e. it will simply\n'
|
||||
m += 'lowercase letter will be treated as a “pad character”, i.e. it will simply\n'
|
||||
m += 'be discarded. Pad characters may be typed before, after, or in the middle\n'
|
||||
m += "of words. For each word, once you've typed {lw} characters total (including\n"
|
||||
m += 'pad characters) any pad character will enter the word.'
|
||||
|
||||
msg(m.format(ml=mn_len,lw=longest_word,lq=g.lq,rq=g.rq))
|
||||
msg(m.format(ml=mn_len,lw=longest_word))
|
||||
|
||||
from string import ascii_lowercase
|
||||
from mmgen.term import get_char_raw
|
||||
|
|
|
|||
|
|
@ -495,8 +495,11 @@ class MMGenToolCmdMnemonic(MMGenToolCmdBase):
|
|||
|
||||
@staticmethod
|
||||
def _xmr_reduce(bytestr):
|
||||
from mmgen.protocol import MoneroProtocol
|
||||
return MoneroProtocol.preprocess_key(bytestr,None)
|
||||
from mmgen.protocol import MoneroProtocol as mp
|
||||
if len(bytestr) != mp.privkey_len:
|
||||
m = '{!r}: invalid bit length for Monero private key (must be {})'
|
||||
die(1,m.format(len(bytestr*8),mp.privkey_len*8))
|
||||
return mp.preprocess_key(bytestr,None)
|
||||
|
||||
def _do_random_mn(self,nbytes:int,fmt:str):
|
||||
assert nbytes in (16,24,32), 'nbytes must be 16, 24 or 32'
|
||||
|
|
@ -891,7 +894,13 @@ class MMGenToolCmdRPC(MMGenToolCmdBase):
|
|||
return ret
|
||||
|
||||
class MMGenToolCmdMonero(MMGenToolCmdBase):
|
||||
"Monero wallet utilities"
|
||||
"""
|
||||
Monero wallet utilities
|
||||
|
||||
Note that the use of these commands requires private data to be exposed on
|
||||
a network-connected machine in order to unlock the Monero wallets. This is
|
||||
a violation of MMGen's security policy.
|
||||
"""
|
||||
|
||||
_monero_chain_height = None
|
||||
monerod_args = []
|
||||
|
|
@ -918,14 +927,14 @@ class MMGenToolCmdMonero(MMGenToolCmdBase):
|
|||
xmr_keyaddrfile:str,
|
||||
blockheight:'(default: current height)' = 0,
|
||||
addrs:'(integer range or list)' = ''):
|
||||
"create Monero wallets from key-address list"
|
||||
"create Monero wallets from a key-address list"
|
||||
return self.monero_wallet_ops( infile = xmr_keyaddrfile,
|
||||
op = 'create',
|
||||
blockheight = blockheight,
|
||||
addrs = addrs)
|
||||
|
||||
def syncmonerowallets(self,xmr_keyaddrfile:str,addrs:'(integer range or list)'=''):
|
||||
"sync Monero wallets from key-address list"
|
||||
"sync Monero wallets from a key-address list"
|
||||
return self.monero_wallet_ops(infile=xmr_keyaddrfile,op='sync',addrs=addrs)
|
||||
|
||||
def monero_wallet_ops(self,infile:str,op:str,blockheight=0,addrs='',monerod_args=[]):
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ common.py: Shared routines and data for the MMGen test suites
|
|||
class TestSuiteException(Exception): pass
|
||||
class TestSuiteFatalException(Exception): pass
|
||||
|
||||
import os
|
||||
import os,time
|
||||
from mmgen.common import *
|
||||
from mmgen.devtools import *
|
||||
|
||||
|
|
@ -166,13 +166,18 @@ def iqmsg_r(s):
|
|||
if not opt.quiet: omsg_r(s)
|
||||
|
||||
def start_test_daemons(*network_ids):
|
||||
if hasattr(opt,'no_daemon_autostart') and opt.no_daemon_autostart:
|
||||
return
|
||||
return test_daemons_ops(*network_ids,op='start')
|
||||
|
||||
def stop_test_daemons(*network_ids):
|
||||
if hasattr(opt,'no_daemon_stop') and opt.no_daemon_stop:
|
||||
return
|
||||
return test_daemons_ops(*network_ids,op='stop')
|
||||
|
||||
def restart_test_daemons(*network_ids):
|
||||
return test_daemons_ops(*network_ids,op='restart')
|
||||
stop_test_daemons(*network_ids)
|
||||
return start_test_daemons(*network_ids)
|
||||
|
||||
def test_daemons_ops(*network_ids,op):
|
||||
if opt.no_daemon_autostart:
|
||||
|
|
|
|||
|
|
@ -37,18 +37,19 @@ rounds=100 rounds_min=20 rounds_mid=250 rounds_max=500
|
|||
xmr_addrs='3,99,2,22-24,101-104'
|
||||
|
||||
dfl_tests='misc obj color unit hash ref altref alts xmr eth autosign btc btc_tn btc_rt bch bch_rt ltc ltc_rt tool tool2 gen'
|
||||
extra_tests='autosign_minimal autosign_live etc ltc_tn bch_tn'
|
||||
noalt_tests='misc obj color unit hash ref autosign_minimal btc btc_tn btc_rt tool tool2 gen'
|
||||
extra_tests='autosign_btc autosign_live etc ltc_tn bch_tn'
|
||||
noalt_tests='misc obj color unit hash ref autosign_btc btc btc_tn btc_rt tool tool2 gen'
|
||||
quick_tests='misc obj color unit hash ref altref alts xmr eth autosign btc btc_rt tool tool2 gen'
|
||||
qskip_tests='btc_tn bch bch_rt ltc ltc_rt'
|
||||
|
||||
PROGNAME=$(basename $0)
|
||||
while getopts hbCfFi:I:lOpRtvV OPT
|
||||
while getopts hAbCfFi:I:lOpRtvV OPT
|
||||
do
|
||||
case "$OPT" in
|
||||
h) printf " %-16s Test MMGen release\n" "${PROGNAME}:"
|
||||
echo " USAGE: $PROGNAME [options] [tests or test group]"
|
||||
echo " OPTIONS: '-h' Print this help message"
|
||||
echo " '-A' Skip tests requiring altcoin modules or daemons"
|
||||
echo " '-b' Buffer keypresses for all invocations of 'test/test.py'"
|
||||
echo " '-C' Run tests in coverage mode"
|
||||
echo " '-f' Speed up the tests by using fewer rounds"
|
||||
|
|
@ -100,6 +101,7 @@ do
|
|||
echo
|
||||
echo " By default, all tests are run"
|
||||
exit ;;
|
||||
A) SKIP_ALT=1 ;;
|
||||
b) test_py+=" --buf-keypress" ;;
|
||||
C) mkdir -p 'test/trace'
|
||||
touch 'test/trace.acc'
|
||||
|
|
@ -151,7 +153,7 @@ case $1 in
|
|||
'') tests=$dfl_tests ;;
|
||||
'default') tests=$dfl_tests ;;
|
||||
'extra') tests=$extra_tests ;;
|
||||
'noalt') tests=$noalt_tests ;;
|
||||
'noalt') tests=$noalt_tests SKIP_ALT=1 ;;
|
||||
'quick') tests=$quick_tests ;;
|
||||
'qskip') tests=$qskip_tests ;;
|
||||
*) tests="$*" ;;
|
||||
|
|
@ -316,16 +318,16 @@ t_alts="
|
|||
# keyconv
|
||||
$gentest_py --all --type=legacy 2:keyconv $rounds
|
||||
$gentest_py --all --type=compressed 2:keyconv $rounds
|
||||
# ethkey
|
||||
$gentest_py --all 2:ethkey $rounds
|
||||
"
|
||||
|
||||
[ "$MSYS2" ] || { # no moneropy (pysha3), zcash-mini (golang), ethkey (?)
|
||||
[ "$MSYS2" ] || { # no moneropy (pysha3), zcash-mini (golang)
|
||||
t_alts+="
|
||||
# moneropy
|
||||
$gentest_py --all --coin=xmr 2:moneropy $rounds_min # very slow, be patient!
|
||||
# zcash-mini
|
||||
$gentest_py --all 2:zcash-mini $rounds_mid
|
||||
# ethkey
|
||||
$gentest_py --all 2:ethkey $rounds
|
||||
"
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +345,7 @@ else
|
|||
mkdir -p $TMPDIR
|
||||
fi
|
||||
|
||||
mmgen_tool_xmr="$mmgen_tool -q --accept-defaults --outdir $TMPDIR"
|
||||
mmgen_tool_xmr="$mmgen_tool -q --accept-defaults --outdir $TMPDIR --monero-wallet-rpc-password=passw0rd"
|
||||
i_xmr='Monero'
|
||||
s_xmr='Testing key-address file generation and wallet creation and sync operations for Monero'
|
||||
s_xmr='The monerod (mainnet) daemon must be running for the following tests'
|
||||
|
|
@ -387,10 +389,10 @@ s_autosign='The bitcoin, bitcoin-abc and litecoin mainnet and testnet daemons mu
|
|||
t_autosign="$test_py autosign"
|
||||
f_autosign='Autosign test completed'
|
||||
|
||||
i_autosign_minimal='Autosign Minimal'
|
||||
s_autosign_minimal='The bitcoin mainnet and testnet daemons must be running for the following test'
|
||||
t_autosign_minimal="$test_py autosign_minimal"
|
||||
f_autosign_minimal='Autosign Minimal test completed'
|
||||
i_autosign_btc='Autosign BTC'
|
||||
s_autosign_btc='The bitcoin mainnet and testnet daemons must be running for the following test'
|
||||
t_autosign_btc="$test_py autosign_btc"
|
||||
f_autosign_btc='Autosign BTC test completed'
|
||||
|
||||
i_autosign_live='Autosign Live'
|
||||
s_autosign_live="The bitcoin mainnet and testnet daemons must be running for the following test\n"
|
||||
|
|
@ -402,7 +404,7 @@ f_autosign_live='Autosign Live test completed'
|
|||
i_btc='Bitcoin mainnet'
|
||||
s_btc='The bitcoin (mainnet) daemon must both be running for the following tests'
|
||||
t_btc="
|
||||
$test_py --exclude regtest,autosign_minimal,ref_altcoin
|
||||
$test_py --exclude regtest,autosign,ref_altcoin
|
||||
$test_py --segwit
|
||||
$test_py --segwit-random
|
||||
$test_py --bech32
|
||||
|
|
@ -473,7 +475,6 @@ t_tool2="
|
|||
$tooltest2_py --tool-api --coin=eth
|
||||
$tooltest2_py --tool-api --coin=xmr
|
||||
$tooltest2_py --tool-api --coin=zec
|
||||
$tooltest2_py --fork # run once with --fork so commands are actually executed
|
||||
$tooltest2_py
|
||||
$tooltest2_py --testnet=1
|
||||
$tooltest2_py --coin=ltc
|
||||
|
|
@ -488,8 +489,10 @@ t_tool2="
|
|||
$tooltest2_py --coin=eth --token=mm1
|
||||
$tooltest2_py --coin=eth --token=mm1 --testnet=1
|
||||
$tooltest2_py --coin=etc
|
||||
$tooltest2_py --fork # run once with --fork so commands are actually executed
|
||||
"
|
||||
f_tool2='tooltest2 tests completed'
|
||||
[ "$SKIP_ALT" ] && t_tool2_skip='17 18'
|
||||
|
||||
i_tool='Tooltest'
|
||||
s_tool="The following tests will run '$tooltest_py' for all supported coins"
|
||||
|
|
|
|||
16
test/test.py
16
test/test.py
|
|
@ -476,7 +476,7 @@ class CmdGroupMgr(object):
|
|||
# 'chainsplit': ('TestSuiteChainsplit',{}),
|
||||
'ethdev': ('TestSuiteEthdev',{}),
|
||||
'autosign': ('TestSuiteAutosign',{}),
|
||||
'autosign_minimal': ('TestSuiteAutosignMinimal',{'modname':'autosign'}),
|
||||
'autosign_btc': ('TestSuiteAutosignBTC',{'modname':'autosign'}),
|
||||
'autosign_live': ('TestSuiteAutosignLive',{'modname':'autosign'}),
|
||||
'create_ref_tx': ('TestSuiteRefTX',{'modname':'misc','full_data':True}),
|
||||
}
|
||||
|
|
@ -491,7 +491,7 @@ class CmdGroupMgr(object):
|
|||
'tool',
|
||||
'input',
|
||||
'output',
|
||||
'autosign_minimal',
|
||||
'autosign',
|
||||
'regtest',
|
||||
'ethdev')
|
||||
|
||||
|
|
@ -600,6 +600,7 @@ class TestSuiteRunner(object):
|
|||
self.rebuild_list = OrderedDict()
|
||||
self.gm = CmdGroupMgr()
|
||||
self.repo_root = repo_root
|
||||
self.skipped_warnings = []
|
||||
|
||||
if opt.log:
|
||||
self.log_fd = open(log_file,'a')
|
||||
|
|
@ -863,6 +864,12 @@ class TestSuiteRunner(object):
|
|||
if cmd == opt.exit_after:
|
||||
sys.exit(0)
|
||||
|
||||
def warn_skipped(self):
|
||||
if self.skipped_warnings:
|
||||
print(yellow('The following tests were skipped and may require attention:'))
|
||||
r = '-' * 72 + '\n'
|
||||
print(r+('\n'+r).join(self.skipped_warnings))
|
||||
|
||||
def process_retval(self,cmd,ret):
|
||||
if type(ret).__name__ == 'MMGenPexpect':
|
||||
ret.ok()
|
||||
|
|
@ -872,6 +879,9 @@ class TestSuiteRunner(object):
|
|||
self.cmd_total += 1
|
||||
elif ret == 'skip':
|
||||
pass
|
||||
elif type(ret) == tuple and ret[0] == 'skip_warn':
|
||||
self.skipped_warnings.append(
|
||||
'Test {!r} was skipped:\n {}'.format(cmd,'\n '.join(ret[1].split('\n'))))
|
||||
else:
|
||||
rdie(1,'{!r} returned {}'.format(cmd,ret))
|
||||
|
||||
|
|
@ -942,9 +952,11 @@ start_test_daemons(network_id)
|
|||
try:
|
||||
tr = TestSuiteRunner(data_dir,trash_dir)
|
||||
tr.run_tests(usr_args)
|
||||
tr.warn_skipped()
|
||||
stop_test_daemons(network_id)
|
||||
except KeyboardInterrupt:
|
||||
stop_test_daemons(network_id)
|
||||
tr.warn_skipped()
|
||||
die(1,'\ntest.py exiting at user request')
|
||||
except TestSuiteException as e:
|
||||
ydie(1,e.args[0])
|
||||
|
|
|
|||
|
|
@ -40,14 +40,14 @@ class TestSuiteAutosign(TestSuiteBase):
|
|||
)
|
||||
|
||||
def autosign_live(self):
|
||||
return self.autosign_minimal(live=True)
|
||||
return self.autosign_btc(live=True)
|
||||
|
||||
def autosign_minimal(self,live=False):
|
||||
def autosign_btc(self,live=False):
|
||||
return self.autosign(
|
||||
coins=['btc','eth'],
|
||||
coins=['btc'],
|
||||
daemon_coins=['btc'],
|
||||
txfiles=['btc','eth','mm1','etc'],
|
||||
txcount=8,
|
||||
txfiles=['btc'],
|
||||
txcount=3,
|
||||
live=live)
|
||||
|
||||
# tests everything except device detection, mount/unmount
|
||||
|
|
@ -228,13 +228,13 @@ class TestSuiteAutosign(TestSuiteBase):
|
|||
stop_test_daemons(*network_ids)
|
||||
return ret
|
||||
|
||||
class TestSuiteAutosignMinimal(TestSuiteAutosign):
|
||||
'autosigning with BTC, ETH and ETC'
|
||||
class TestSuiteAutosignBTC(TestSuiteAutosign):
|
||||
'autosigning with BTC'
|
||||
cmd_group = (
|
||||
('autosign_minimal', 'transaction autosigning (BTC,ETH,ETC)'),
|
||||
('autosign_btc', 'transaction autosigning (BTC only)'),
|
||||
)
|
||||
|
||||
class TestSuiteAutosignLive(TestSuiteAutosignMinimal):
|
||||
class TestSuiteAutosignLive(TestSuiteAutosignBTC):
|
||||
'live autosigning operations with device insertion/removal and LED check'
|
||||
cmd_group = (
|
||||
('autosign_live', 'transaction autosigning (BTC,ETH,ETC - test device insertion/removal + LED)'),
|
||||
|
|
|
|||
|
|
@ -135,16 +135,18 @@ class TestSuiteInput(TestSuiteBase):
|
|||
|
||||
def password_entry_noecho(self):
|
||||
if self.skip_for_win():
|
||||
msg('Perform this test by hand on MSWin with non-ASCII password abc-α:')
|
||||
msg(' test/misc/password_entry.py')
|
||||
return 'skip' # getpass() can't handle utf8, and pexpect double-escapes utf8, so skip
|
||||
m = "getpass() doesn't work with pexpect.popen_spawn!\n"
|
||||
m += 'Perform the following test by hand with non-ASCII password abc-α:\n'
|
||||
m += ' test/misc/password_entry.py'
|
||||
return ('skip_warn',m)
|
||||
return self.password_entry('Enter passphrase: ',[])
|
||||
|
||||
def password_entry_echo(self):
|
||||
if self.skip_for_win():
|
||||
msg('Perform this test by hand on MSWin with non-ASCII password abc-α:')
|
||||
msg(' test/misc/password_entry.py --echo-passphrase')
|
||||
return 'skip' # pexpect double-escapes utf8, so skip
|
||||
m = "getpass() doesn't work with pexpect.popen_spawn!\n"
|
||||
m += 'Perform the following test by hand with non-ASCII password abc-α:\n'
|
||||
m += ' test/misc/password_entry.py --echo-passphrase'
|
||||
return ('skip_warn',m)
|
||||
return self.password_entry('Enter passphrase (echoed): ',['--echo-passphrase'])
|
||||
|
||||
def _user_seed_entry(self,fmt,usr_rand=False,out_fmt=None):
|
||||
|
|
|
|||
|
|
@ -231,12 +231,12 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared):
|
|||
|
||||
def ref_segwitaddrfile_chk(self):
|
||||
if not 'S' in g.proto.mmtypes:
|
||||
return skip('not supported')
|
||||
return skip('not supported by {}'.format(g.proto.__name__))
|
||||
return self.ref_addrfile_chk(ftype='segwitaddr',pat='{}.*Segwit'.format(nw_name))
|
||||
|
||||
def ref_bech32addrfile_chk(self):
|
||||
if not 'B' in g.proto.mmtypes:
|
||||
return skip('not supported')
|
||||
return skip('not supported by {}'.format(g.proto.__name__))
|
||||
return self.ref_addrfile_chk(ftype='bech32addr',pat='{}.*Bech32'.format(nw_name))
|
||||
|
||||
def ref_keyaddrfile_chk(self):
|
||||
|
|
|
|||
|
|
@ -150,10 +150,11 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
|
|||
fn = os.path.split(t.written_to_file(capfirst(ocls.desc)))[-1]
|
||||
import re
|
||||
idx = int(self.test_name[-1]) - 1
|
||||
pat = r'{}-[0-9A-F]{{8}}\[{},1\].mmdat'.format(
|
||||
pat = r'{}-[0-9A-F]{{8}}\[{},1\]{}.mmdat'.format(
|
||||
self.chk_data['sids'][idx],
|
||||
self.chk_data['lens'][idx] )
|
||||
assert re.match(pat,fn)
|
||||
self.chk_data['lens'][idx],
|
||||
'-α' if g.debug_utf8 else '')
|
||||
assert re.match(pat,fn),'{} != {}'.format(pat,fn)
|
||||
sid = os.path.basename(fn.split('-')[0])
|
||||
cmp_or_die(sid,self.seed_id,desc='Seed ID')
|
||||
return t
|
||||
|
|
@ -170,9 +171,9 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
|
|||
if re_pat:
|
||||
import re
|
||||
pat = re_pat.format(sid,slen)
|
||||
assert re.match(pat,fn),'{} {}'.format(pat,fn)
|
||||
assert re.match(pat,fn),'{} != {}'.format(pat,fn)
|
||||
else:
|
||||
cmp_or_die('{}[{}].{}'.format(sid,slen,wcls.ext),fn)
|
||||
cmp_or_die('{}[{}]{}.{}'.format(sid,slen,'-α' if g.debug_utf8 else '',wcls.ext),fn)
|
||||
return t
|
||||
|
||||
def ref_walletconv_words(self): return self.ref_walletconv(ofmt='mn')
|
||||
|
|
@ -184,7 +185,7 @@ class TestSuiteRef3Seed(TestSuiteBase,TestSuiteShared):
|
|||
|
||||
def ref_walletconv_incog(self,ofmt='incog',ext='mmincog'):
|
||||
args = ['-r0','-p1']
|
||||
pat = r'{}-[0-9A-F]{{8}}-[0-9A-F]{{8}}\[{},1\].' + ext
|
||||
pat = r'{}-[0-9A-F]{{8}}-[0-9A-F]{{8}}\[{},1\]' + ('-α' if g.debug_utf8 else '') + '.' + ext
|
||||
return self.ref_walletconv(ofmt=ofmt,extra_args=args,re_pat=pat)
|
||||
|
||||
def ref_walletconv_xincog(self):
|
||||
|
|
|
|||
|
|
@ -630,9 +630,11 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared):
|
|||
return t
|
||||
|
||||
def _get_mempool(self):
|
||||
disable_debug()
|
||||
if not g.debug_utf8:
|
||||
disable_debug()
|
||||
ret = self.spawn('mmgen-regtest',['mempool']).read()
|
||||
restore_debug()
|
||||
if not g.debug_utf8:
|
||||
restore_debug()
|
||||
m = re.search(r'(\[\s*"[a-f0-9]{64}"\s*])',ret) # allow for extra output by handler at end
|
||||
return json.loads(m.group(1))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue