2018-10-30 16:23:12 +00:00
|
|
|
#!/usr/bin/env python3
|
2018-11-17 20:34:04 +00:00
|
|
|
#
|
2024-10-18 10:32:06 +00:00
|
|
|
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
2025-02-16 14:42:27 +00:00
|
|
|
# Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
|
2016-02-28 16:41:43 +03:00
|
|
|
#
|
|
|
|
|
# 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/>.
|
|
|
|
|
|
|
|
|
|
"""
|
2023-10-13 09:51:14 +00:00
|
|
|
test/cmdtest.py: Command test runner for the MMGen wallet system
|
2016-02-28 16:41:43 +03:00
|
|
|
"""
|
2015-01-03 00:14:40 +03:00
|
|
|
|
2025-03-18 11:09:51 +03:00
|
|
|
def check_segwit_opts(proto):
|
2024-10-18 10:32:12 +00:00
|
|
|
for k, m in (('segwit', 'S'), ('segwit_random', 'S'), ('bech32', 'B')):
|
|
|
|
|
if getattr(cfg, k) and m not in proto.mmtypes:
|
|
|
|
|
die(1, f'--{k.replace("_", "-")} option incompatible with {proto.cls_name}')
|
2016-02-28 16:41:43 +03:00
|
|
|
|
2024-10-18 10:32:12 +00:00
|
|
|
def create_shm_dir(data_dir, trash_dir):
|
2019-03-02 18:27:53 +00:00
|
|
|
# Laggy flash media can cause pexpect to fail, so create a temporary directory
|
|
|
|
|
# under '/dev/shm' and put datadir and tmpdirs here.
|
|
|
|
|
import shutil
|
2019-10-23 09:31:21 +00:00
|
|
|
from subprocess import run
|
2024-07-27 09:42:50 +00:00
|
|
|
if sys.platform in ('win32', 'darwin'):
|
2024-10-18 10:32:12 +00:00
|
|
|
for tdir in (data_dir, trash_dir):
|
2023-10-11 12:58:51 +00:00
|
|
|
try:
|
|
|
|
|
os.listdir(tdir)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
2018-05-08 10:44:12 +00:00
|
|
|
else:
|
2023-10-11 12:58:51 +00:00
|
|
|
try:
|
|
|
|
|
shutil.rmtree(tdir)
|
2018-05-08 10:44:12 +00:00
|
|
|
except: # we couldn't remove data dir - perhaps regtest daemon is running
|
2019-10-23 09:31:21 +00:00
|
|
|
try:
|
2024-10-18 10:32:12 +00:00
|
|
|
run(['python3', os.path.join('cmds', 'mmgen-regtest'), 'stop'], check=True)
|
2019-10-23 09:31:21 +00:00
|
|
|
except:
|
2024-10-18 10:32:12 +00:00
|
|
|
die(4, f'Unable to remove {tdir!r}!')
|
2018-05-08 10:44:12 +00:00
|
|
|
else:
|
|
|
|
|
time.sleep(2)
|
|
|
|
|
shutil.rmtree(tdir)
|
2024-10-18 10:32:12 +00:00
|
|
|
os.mkdir(tdir, 0o755)
|
2019-03-25 10:07:04 +00:00
|
|
|
shm_dir = 'test'
|
2016-11-23 17:17:08 +03:00
|
|
|
else:
|
2024-10-18 10:32:12 +00:00
|
|
|
tdir, pfx = '/dev/shm', 'mmgen-test-'
|
2016-12-12 00:30:23 +03:00
|
|
|
try:
|
2024-10-18 10:32:12 +00:00
|
|
|
run(f'rm -rf {tdir}/{pfx}*', shell=True, check=True)
|
2016-12-12 00:30:23 +03:00
|
|
|
except Exception as e:
|
2024-10-18 10:32:12 +00:00
|
|
|
die(2, f'Unable to delete directory tree {tdir}/{pfx}* ({e.args[0]})')
|
2016-12-12 00:30:23 +03:00
|
|
|
try:
|
|
|
|
|
import tempfile
|
2024-10-18 10:32:12 +00:00
|
|
|
shm_dir = str(tempfile.mkdtemp('', pfx, tdir))
|
2016-12-12 00:30:23 +03:00
|
|
|
except Exception as e:
|
2024-10-18 10:32:12 +00:00
|
|
|
die(2, f'Unable to create temporary directory in {tdir} ({e.args[0]})')
|
2019-03-02 18:27:53 +00:00
|
|
|
|
2024-10-18 10:32:12 +00:00
|
|
|
dest = os.path.join(shm_dir, os.path.basename(trash_dir))
|
|
|
|
|
os.mkdir(dest, 0o755)
|
2020-05-10 13:39:53 +00:00
|
|
|
|
2024-10-18 10:32:12 +00:00
|
|
|
run(f'rm -rf {trash_dir}', shell=True, check=True)
|
|
|
|
|
os.symlink(dest, trash_dir)
|
2019-03-02 18:27:53 +00:00
|
|
|
|
2024-10-18 10:32:12 +00:00
|
|
|
dest = os.path.join(shm_dir, os.path.basename(data_dir))
|
|
|
|
|
shutil.move(data_dir, dest) # data_dir was created by Config()
|
|
|
|
|
os.symlink(dest, data_dir)
|
2019-03-02 18:27:53 +00:00
|
|
|
|
|
|
|
|
return shm_dir
|
|
|
|
|
|
2025-03-18 11:09:51 +03:00
|
|
|
import sys, os, time
|
2021-10-03 17:40:02 +00:00
|
|
|
|
2024-07-20 16:40:57 +00:00
|
|
|
# overlay must be set up before importing mmgen mods!
|
|
|
|
|
try:
|
|
|
|
|
from include.test_init import repo_root
|
|
|
|
|
except ImportError:
|
|
|
|
|
from test.include.test_init import repo_root
|
2019-03-02 18:27:53 +00:00
|
|
|
|
2025-03-18 11:09:51 +03:00
|
|
|
from mmgen.cfg import Config
|
|
|
|
|
from mmgen.color import red, yellow, green, blue, init_color
|
|
|
|
|
from mmgen.util import msg, Msg, rmsg, die
|
2023-10-03 14:27:56 +00:00
|
|
|
|
|
|
|
|
from test.include.common import (
|
|
|
|
|
set_globals,
|
2023-10-13 09:51:14 +00:00
|
|
|
cmdtest_py_log_fn,
|
|
|
|
|
cmdtest_py_error_fn,
|
2023-10-03 14:27:56 +00:00
|
|
|
mk_tmpdir,
|
2025-03-18 11:09:51 +03:00
|
|
|
stop_test_daemons)
|
2023-09-29 12:24:21 +00:00
|
|
|
|
2022-02-07 21:08:08 +00:00
|
|
|
try:
|
2024-10-18 10:32:12 +00:00
|
|
|
os.unlink(os.path.join(repo_root, cmdtest_py_error_fn))
|
2022-02-07 21:08:08 +00:00
|
|
|
except:
|
|
|
|
|
pass
|
2019-03-02 18:27:53 +00:00
|
|
|
|
|
|
|
|
os.environ['MMGEN_QUIET'] = '0' # for this script and spawned scripts
|
2016-11-21 19:59:03 +03:00
|
|
|
|
2019-03-26 12:59:30 +00:00
|
|
|
opts_data = {
|
2022-10-29 20:10:23 +00:00
|
|
|
'sets': [
|
2024-10-18 10:32:12 +00:00
|
|
|
('list_current_cmd_groups', True, 'list_cmd_groups', True),
|
|
|
|
|
('demo', True, 'exact_output', True),
|
|
|
|
|
('demo', True, 'buf_keypress', True),
|
|
|
|
|
('demo', True, 'pexpect_spawn', True),
|
2022-10-29 20:10:23 +00:00
|
|
|
],
|
2019-03-26 12:59:30 +00:00
|
|
|
'text': {
|
2023-11-27 09:15:07 +00:00
|
|
|
'desc': 'High-level tests for the MMGen Wallet suite',
|
2022-07-29 16:45:31 +00:00
|
|
|
'usage':'[options] [command [..command]] | [command_group[.command_subgroup][:command]]',
|
2022-02-03 20:40:42 +00:00
|
|
|
'options': """
|
2018-10-13 15:00:03 +00:00
|
|
|
-h, --help Print this help message
|
2024-10-08 12:55:58 +00:00
|
|
|
--, --longhelp Print help message for long (global) options
|
2022-05-03 21:01:05 +00:00
|
|
|
-a, --no-altcoin Skip altcoin tests (WIP)
|
2019-12-07 12:45:04 +00:00
|
|
|
-A, --no-daemon-autostart Don't start and stop daemons automatically
|
2018-10-13 15:00:03 +00:00
|
|
|
-B, --bech32 Generate and use Bech32 addresses
|
|
|
|
|
-b, --buf-keypress Use buffered keypresses as with real human input
|
2019-02-06 11:05:37 +00:00
|
|
|
(often required on slow systems, or under emulation)
|
2018-10-13 15:00:03 +00:00
|
|
|
-c, --print-cmdline Print the command line of each spawned command
|
|
|
|
|
-C, --coverage Produce code coverage info using trace module
|
|
|
|
|
-x, --debug-pexpect Produce debugging output for pexpect calls
|
2022-10-29 20:10:23 +00:00
|
|
|
--, --demo Add extra delay after each send to make input visible.
|
|
|
|
|
Implies --exact-output --pexpect-spawn --buf-keypress
|
2022-12-01 12:32:31 +00:00
|
|
|
-d, --deps-only Run a command or command subgroup’s dependencies without
|
|
|
|
|
running the command or command group itself.
|
2018-10-13 15:00:03 +00:00
|
|
|
-D, --no-daemon-stop Don't stop auto-started daemons after running tests
|
|
|
|
|
-E, --direct-exec Bypass pexpect and execute a command directly (for
|
|
|
|
|
debugging only)
|
|
|
|
|
-e, --exact-output Show the exact output of the MMGen script(s) being run
|
2019-03-02 18:27:53 +00:00
|
|
|
-G, --exclude-groups=G Exclude the specified command groups (comma-separated)
|
2025-03-29 09:30:16 +00:00
|
|
|
-k, --devnet-block-period=N Block time for Ethereum devnet bump tests
|
2022-07-29 16:45:30 +00:00
|
|
|
-l, --list-cmds List the test script’s available commands
|
2022-07-29 16:45:31 +00:00
|
|
|
-L, --list-cmd-groups List the test script’s command groups and subgroups
|
2019-12-07 12:20:21 +00:00
|
|
|
-g, --list-current-cmd-groups List command groups for current configuration
|
2018-10-13 15:00:03 +00:00
|
|
|
-n, --names Display command names instead of descriptions
|
2021-09-29 21:17:56 +00:00
|
|
|
-N, --no-timings Suppress display of timing information
|
2022-02-03 20:40:42 +00:00
|
|
|
-o, --log Log commands to file {lf!r}
|
2019-03-02 18:27:53 +00:00
|
|
|
-O, --pexpect-spawn Use pexpect.spawn instead of popen_spawn (much slower,
|
|
|
|
|
kut does real terminal emulation)
|
2018-10-13 15:00:03 +00:00
|
|
|
-p, --pause Pause between tests, resuming on keypress
|
|
|
|
|
-P, --profile Record the execution time of each script
|
|
|
|
|
-q, --quiet Produce minimal output. Suppress dependency info
|
|
|
|
|
-r, --resume=c Resume at command 'c' after interrupted run
|
2020-05-10 13:39:53 +00:00
|
|
|
-R, --resume-after=c Same, but resume at command following 'c'
|
2022-02-07 21:08:09 +00:00
|
|
|
-t, --step After resuming, execute one command and stop
|
2018-10-13 15:00:03 +00:00
|
|
|
-S, --skip-deps Skip dependency checking for command
|
|
|
|
|
-u, --usr-random Get random data interactively from user
|
2019-03-23 14:30:47 +00:00
|
|
|
-T, --pexpect-timeout=T Set the timeout for pexpect
|
2018-10-13 15:00:03 +00:00
|
|
|
-v, --verbose Produce more verbose output
|
2022-07-29 16:45:30 +00:00
|
|
|
-W, --no-dw-delete Don't remove default wallet from data dir after dw tests
|
|
|
|
|
are done
|
2018-10-13 15:00:03 +00:00
|
|
|
-X, --exit-after=C Exit after command 'C'
|
2019-02-19 09:02:49 +00:00
|
|
|
-y, --segwit Generate and use Segwit addresses
|
|
|
|
|
-Y, --segwit-random Generate and use a random mix of Segwit and Legacy addrs
|
2019-03-26 12:59:30 +00:00
|
|
|
""",
|
|
|
|
|
'notes': """
|
2016-11-21 19:59:03 +03:00
|
|
|
|
2022-07-29 16:45:30 +00:00
|
|
|
If no command is given, the whole test suite is run for the currently
|
|
|
|
|
specified coin (default BTC).
|
2022-07-29 16:45:31 +00:00
|
|
|
|
|
|
|
|
For traceback output and error file support, set the EXEC_WRAPPER_TRACEBACK
|
|
|
|
|
environment var
|
2016-11-21 19:59:03 +03:00
|
|
|
"""
|
2019-03-26 12:59:30 +00:00
|
|
|
},
|
2022-02-03 20:40:42 +00:00
|
|
|
'code': {
|
2024-10-18 10:32:12 +00:00
|
|
|
'options': lambda proto, help_notes, s: s.format(
|
2023-10-13 09:51:14 +00:00
|
|
|
lf = cmdtest_py_log_fn
|
2022-02-03 20:40:42 +00:00
|
|
|
)
|
|
|
|
|
}
|
2016-11-21 19:59:03 +03:00
|
|
|
}
|
|
|
|
|
|
2020-05-26 14:53:44 +00:00
|
|
|
# we need some opt values before running opts.init, so parse without initializing:
|
2024-10-18 10:32:12 +00:00
|
|
|
po = Config(opts_data=opts_data, parse_only=True)._parsed_opts
|
2022-02-03 20:40:42 +00:00
|
|
|
|
2023-09-29 12:24:22 +00:00
|
|
|
data_dir = Config.test_datadir
|
2016-11-21 19:59:03 +03:00
|
|
|
|
2019-03-02 18:27:53 +00:00
|
|
|
# step 1: delete data_dir symlink in ./test;
|
2024-02-22 12:48:12 +00:00
|
|
|
if not po.user_opts.get('skip_deps'):
|
2023-10-11 12:58:51 +00:00
|
|
|
try:
|
|
|
|
|
os.unlink(data_dir)
|
|
|
|
|
except:
|
|
|
|
|
pass
|
2017-10-28 00:11:00 +03:00
|
|
|
|
2024-02-22 12:48:12 +00:00
|
|
|
# step 2: opts.init will create new data_dir in ./test (if not po.user_opts['skip_deps'])
|
2023-04-04 16:04:10 +00:00
|
|
|
cfg = Config(opts_data=opts_data)
|
2023-03-28 18:14:37 +00:00
|
|
|
|
2023-11-21 15:48:10 +00:00
|
|
|
if cfg.no_altcoin and cfg.coin != 'BTC':
|
2024-10-18 10:32:12 +00:00
|
|
|
die(1, f'--no-altcoin incompatible with --coin={cfg.coin}')
|
2023-11-21 15:48:10 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
set_globals(cfg)
|
|
|
|
|
|
|
|
|
|
type(cfg)._reset_ok += (
|
2022-08-04 13:44:31 +00:00
|
|
|
'no_daemon_autostart',
|
|
|
|
|
'names',
|
|
|
|
|
'no_timings',
|
|
|
|
|
'exit_after',
|
|
|
|
|
'resuming',
|
2024-10-18 10:32:12 +00:00
|
|
|
'skipping_deps')
|
2020-06-01 09:25:56 +00:00
|
|
|
|
2024-10-18 10:32:12 +00:00
|
|
|
cfg.resuming = any(k in po.user_opts for k in ('resume', 'resume_after'))
|
2023-03-28 18:14:37 +00:00
|
|
|
cfg.skipping_deps = cfg.resuming or 'skip_deps' in po.user_opts
|
|
|
|
|
|
|
|
|
|
cmd_args = cfg._args
|
2017-11-13 22:50:35 +03:00
|
|
|
|
2023-10-13 09:51:12 +00:00
|
|
|
if cfg.pexpect_spawn and sys.platform == 'win32':
|
2024-10-18 10:32:12 +00:00
|
|
|
die(1, '--pexpect-spawn option not supported on Windows platform, exiting')
|
2022-11-01 14:37:06 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if cfg.daemon_id and cfg.daemon_id in cfg.blacklisted_daemons.split():
|
2024-10-18 10:32:12 +00:00
|
|
|
die(1, f'cmdtest.py: daemon {cfg.daemon_id!r} blacklisted, exiting')
|
2022-06-13 17:30:22 +00:00
|
|
|
|
2019-03-02 18:27:53 +00:00
|
|
|
# step 3: move data_dir to /dev/shm and symlink it back to ./test:
|
2024-10-18 10:32:12 +00:00
|
|
|
trash_dir = os.path.join('test', 'trash')
|
|
|
|
|
trash_dir2 = os.path.join('test', 'trash2')
|
2020-05-28 09:53:34 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if not cfg.skipping_deps:
|
2024-10-18 10:32:12 +00:00
|
|
|
shm_dir = create_shm_dir(data_dir, trash_dir)
|
2017-10-28 00:11:00 +03:00
|
|
|
|
2025-03-18 11:09:51 +03:00
|
|
|
check_segwit_opts(cfg._proto)
|
2017-10-03 22:26:24 +03:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
testing_segwit = cfg.segwit or cfg.segwit_random or cfg.bech32
|
2021-10-08 16:44:56 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if cfg.test_suite_deterministic:
|
|
|
|
|
cfg.no_timings = True
|
2021-10-03 17:40:03 +00:00
|
|
|
init_color(num_colors=0)
|
2023-05-23 12:12:33 +00:00
|
|
|
os.environ['MMGEN_DISABLE_COLOR'] = '1' # for this script and spawned scripts
|
2021-10-03 17:40:03 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if cfg.profile:
|
|
|
|
|
cfg.names = True
|
2018-03-09 11:29:58 +00:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if cfg.exact_output:
|
2023-09-29 12:24:22 +00:00
|
|
|
qmsg = qmsg_r = lambda s: None
|
2023-03-28 18:14:37 +00:00
|
|
|
else:
|
|
|
|
|
qmsg = cfg._util.qmsg
|
|
|
|
|
qmsg_r = cfg._util.qmsg_r
|
2017-07-27 22:55:52 +03:00
|
|
|
|
2023-03-28 18:14:37 +00:00
|
|
|
if cfg.skipping_deps:
|
|
|
|
|
cfg.no_daemon_autostart = True
|
2020-05-10 13:39:53 +00:00
|
|
|
|
2025-03-29 09:30:15 +00:00
|
|
|
from test.cmdtest_d.include.cfg import cfgs
|
2018-07-28 13:52:43 +00:00
|
|
|
|
2019-03-02 18:27:53 +00:00
|
|
|
def list_cmds():
|
2022-07-29 16:45:30 +00:00
|
|
|
|
|
|
|
|
def gen_output():
|
|
|
|
|
|
2025-03-29 09:30:15 +00:00
|
|
|
from test.cmdtest_d.include.group_mgr import CmdGroupMgr
|
2025-03-18 11:09:51 +03:00
|
|
|
gm = CmdGroupMgr(cfg)
|
2024-10-18 10:32:12 +00:00
|
|
|
cw, d = 0, []
|
2022-07-29 16:45:30 +00:00
|
|
|
|
|
|
|
|
yield green('AVAILABLE COMMANDS:')
|
|
|
|
|
|
|
|
|
|
for gname in gm.cmd_groups:
|
2025-03-18 20:09:59 +03:00
|
|
|
tg = gm.gm_init_group(cfg, None, gname, None, None)
|
2025-03-19 12:11:26 +03:00
|
|
|
gdesc = tg.__doc__.strip() if tg.__doc__ else type(tg).__name__
|
|
|
|
|
d.append((gname, gdesc, gm.cmd_list, gm.dpy_data))
|
2024-10-18 10:32:12 +00:00
|
|
|
cw = max(max(len(k) for k in gm.dpy_data), cw)
|
2022-07-29 16:45:30 +00:00
|
|
|
|
2025-03-19 12:11:26 +03:00
|
|
|
for gname, gdesc, cmd_list, dpy_data in d:
|
2022-07-29 16:45:30 +00:00
|
|
|
yield '\n'+green(f'{gname!r} - {gdesc}:')
|
2025-03-19 12:11:26 +03:00
|
|
|
for cmd in cmd_list:
|
|
|
|
|
data = dpy_data[cmd]
|
2022-07-29 16:45:30 +00:00
|
|
|
yield ' {:{w}} - {}'.format(
|
|
|
|
|
cmd,
|
2024-10-18 10:32:12 +00:00
|
|
|
(data if isinstance(data, str) else data[1]),
|
|
|
|
|
w = cw)
|
2022-07-29 16:45:30 +00:00
|
|
|
|
2022-10-17 18:37:22 +00:00
|
|
|
from mmgen.ui import do_pager
|
2022-07-29 16:45:30 +00:00
|
|
|
do_pager('\n'.join(gen_output()))
|
ERC20 token support (create/deploy, TX create/sign/send)
This feature is EXPERIMENTAL. Until v0.9.9 is released, mainnet use is
strictly at your own risk!
To test on dev chain, run 'test/test.py -e ethdev'
To test on Kovan, add '--testnet=1' option to all commands below
Transaction example:
Generate some ETH addresses with your default wallet:
$ mmgen-addrgen --coin=eth 1-5
Create an EOS token tracking wallet and import the addresses into it:
$ mmgen-addrimport --coin=eth --token=86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0 ABCDABCD-ETH[1-5].addrs
Send 10+ EOS from an exchange or another wallet to address ABCDABCD:E:1
Create a TX sending 10 EOS to address aabbccdd..., with change to ABCDABCD:E:2:
$ mmgen-txcreate --coin=eth --token=eos aabbccddaabbccddaabbccddaabbccddaabbccdd,10 ABCDABCD:E:2
On your offline machine, sign the TX:
$ mmgen-txsign --coin=eth --token=eos ABC123-EOS[10,50000].rawtx
On your online machine, send the TX:
$ mmgen-txsend --coin=eth --token=eos ABC123-EOS[10,50000].sigtx
View your EOS tracking wallet:
$ mmgen-tool --coin=eth --token=eos twview
Token creation/deployment example:
Install the Solidity compiler ('solc') on your system.
Create a token 'MFT' with default parameters, owned by ddeeff... (ABCDABCD:E:1):
$ scripts/create-token.py --symbol=MFT --name='My First Token' ddeeffddeeffddeeffddeeffddeeffddeeffddee
Deploy the token on the ETH blockchain:
$ mmgen-txdo --coin=eth --tx-gas=200000 --contract-data=SafeMath.bin
$ mmgen-txdo --coin=eth --tx-gas=250000 --contract-data=Owned.bin
$ mmgen-txdo --coin=eth --tx-gas=1100000 --contract-data=Token.bin
...
Token address: abcd1234abcd1234abcd1234abcd1234abcd1234
Create an MFT token tracking wallet and import your ETH addresses into it:
$ mmgen-addrimport --coin=eth --token=abcd1234abcd1234abcd1234abcd1234abcd1234 ABCDABCD-ETH[1-5].addrs
View your MFT tracking wallet:
$ mmgen-tool --coin=eth --token=mft twview
2018-07-25 12:57:04 +00:00
|
|
|
|
2019-03-02 18:27:53 +00:00
|
|
|
def create_tmp_dirs(shm_dir):
|
2024-07-27 09:42:50 +00:00
|
|
|
if sys.platform in ('win32', 'darwin'):
|
2019-03-02 18:27:53 +00:00
|
|
|
for cfg in sorted(cfgs):
|
|
|
|
|
mk_tmpdir(cfgs[cfg]['tmpdir'])
|
|
|
|
|
else:
|
2024-10-18 10:32:12 +00:00
|
|
|
os.makedirs(os.path.join('test', 'tmp'), mode=0o755, exist_ok=True)
|
2019-03-02 18:27:53 +00:00
|
|
|
for cfg in sorted(cfgs):
|
2024-10-18 10:32:12 +00:00
|
|
|
src = os.path.join(shm_dir, cfgs[cfg]['tmpdir'].split('/')[-1])
|
2019-03-02 18:27:53 +00:00
|
|
|
mk_tmpdir(src)
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(cfgs[cfg]['tmpdir'])
|
|
|
|
|
except OSError as e:
|
2022-02-05 13:32:56 +00:00
|
|
|
if e.errno != 2:
|
|
|
|
|
raise
|
2019-03-02 18:27:53 +00:00
|
|
|
finally:
|
2024-10-18 10:32:12 +00:00
|
|
|
os.symlink(src, cfgs[cfg]['tmpdir'])
|
ERC20 token support (create/deploy, TX create/sign/send)
This feature is EXPERIMENTAL. Until v0.9.9 is released, mainnet use is
strictly at your own risk!
To test on dev chain, run 'test/test.py -e ethdev'
To test on Kovan, add '--testnet=1' option to all commands below
Transaction example:
Generate some ETH addresses with your default wallet:
$ mmgen-addrgen --coin=eth 1-5
Create an EOS token tracking wallet and import the addresses into it:
$ mmgen-addrimport --coin=eth --token=86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0 ABCDABCD-ETH[1-5].addrs
Send 10+ EOS from an exchange or another wallet to address ABCDABCD:E:1
Create a TX sending 10 EOS to address aabbccdd..., with change to ABCDABCD:E:2:
$ mmgen-txcreate --coin=eth --token=eos aabbccddaabbccddaabbccddaabbccddaabbccdd,10 ABCDABCD:E:2
On your offline machine, sign the TX:
$ mmgen-txsign --coin=eth --token=eos ABC123-EOS[10,50000].rawtx
On your online machine, send the TX:
$ mmgen-txsend --coin=eth --token=eos ABC123-EOS[10,50000].sigtx
View your EOS tracking wallet:
$ mmgen-tool --coin=eth --token=eos twview
Token creation/deployment example:
Install the Solidity compiler ('solc') on your system.
Create a token 'MFT' with default parameters, owned by ddeeff... (ABCDABCD:E:1):
$ scripts/create-token.py --symbol=MFT --name='My First Token' ddeeffddeeffddeeffddeeffddeeffddeeffddee
Deploy the token on the ETH blockchain:
$ mmgen-txdo --coin=eth --tx-gas=200000 --contract-data=SafeMath.bin
$ mmgen-txdo --coin=eth --tx-gas=250000 --contract-data=Owned.bin
$ mmgen-txdo --coin=eth --tx-gas=1100000 --contract-data=Token.bin
...
Token address: abcd1234abcd1234abcd1234abcd1234abcd1234
Create an MFT token tracking wallet and import your ETH addresses into it:
$ mmgen-addrimport --coin=eth --token=abcd1234abcd1234abcd1234abcd1234abcd1234 ABCDABCD-ETH[1-5].addrs
View your MFT tracking wallet:
$ mmgen-tool --coin=eth --token=mft twview
2018-07-25 12:57:04 +00:00
|
|
|
|
2019-03-02 18:27:53 +00:00
|
|
|
def set_restore_term_at_exit():
|
2024-10-18 10:32:12 +00:00
|
|
|
import termios, atexit
|
2019-03-02 18:27:53 +00:00
|
|
|
fd = sys.stdin.fileno()
|
|
|
|
|
old = termios.tcgetattr(fd)
|
|
|
|
|
def at_exit():
|
|
|
|
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
|
|
|
|
atexit.register(at_exit)
|
ERC20 token support (create/deploy, TX create/sign/send)
This feature is EXPERIMENTAL. Until v0.9.9 is released, mainnet use is
strictly at your own risk!
To test on dev chain, run 'test/test.py -e ethdev'
To test on Kovan, add '--testnet=1' option to all commands below
Transaction example:
Generate some ETH addresses with your default wallet:
$ mmgen-addrgen --coin=eth 1-5
Create an EOS token tracking wallet and import the addresses into it:
$ mmgen-addrimport --coin=eth --token=86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0 ABCDABCD-ETH[1-5].addrs
Send 10+ EOS from an exchange or another wallet to address ABCDABCD:E:1
Create a TX sending 10 EOS to address aabbccdd..., with change to ABCDABCD:E:2:
$ mmgen-txcreate --coin=eth --token=eos aabbccddaabbccddaabbccddaabbccddaabbccdd,10 ABCDABCD:E:2
On your offline machine, sign the TX:
$ mmgen-txsign --coin=eth --token=eos ABC123-EOS[10,50000].rawtx
On your online machine, send the TX:
$ mmgen-txsend --coin=eth --token=eos ABC123-EOS[10,50000].sigtx
View your EOS tracking wallet:
$ mmgen-tool --coin=eth --token=eos twview
Token creation/deployment example:
Install the Solidity compiler ('solc') on your system.
Create a token 'MFT' with default parameters, owned by ddeeff... (ABCDABCD:E:1):
$ scripts/create-token.py --symbol=MFT --name='My First Token' ddeeffddeeffddeeffddeeffddeeffddeeffddee
Deploy the token on the ETH blockchain:
$ mmgen-txdo --coin=eth --tx-gas=200000 --contract-data=SafeMath.bin
$ mmgen-txdo --coin=eth --tx-gas=250000 --contract-data=Owned.bin
$ mmgen-txdo --coin=eth --tx-gas=1100000 --contract-data=Token.bin
...
Token address: abcd1234abcd1234abcd1234abcd1234abcd1234
Create an MFT token tracking wallet and import your ETH addresses into it:
$ mmgen-addrimport --coin=eth --token=abcd1234abcd1234abcd1234abcd1234abcd1234 ABCDABCD-ETH[1-5].addrs
View your MFT tracking wallet:
$ mmgen-tool --coin=eth --token=mft twview
2018-07-25 12:57:04 +00:00
|
|
|
|
2023-10-13 09:51:14 +00:00
|
|
|
if __name__ == '__main__':
|
2015-01-03 00:14:40 +03:00
|
|
|
|
2023-10-13 09:51:14 +00:00
|
|
|
if not cfg.skipping_deps: # do this before list cmds exit, so we stay in sync with shm_dir
|
|
|
|
|
create_tmp_dirs(shm_dir)
|
2015-01-03 00:14:40 +03:00
|
|
|
|
2023-10-13 09:51:14 +00:00
|
|
|
if cfg.list_cmd_groups:
|
2025-03-29 09:30:15 +00:00
|
|
|
from test.cmdtest_d.include.group_mgr import CmdGroupMgr
|
2025-03-18 11:09:51 +03:00
|
|
|
CmdGroupMgr(cfg).list_cmd_groups()
|
2025-03-19 12:11:26 +03:00
|
|
|
sys.exit(0)
|
2023-10-13 09:51:14 +00:00
|
|
|
elif cfg.list_cmds:
|
|
|
|
|
list_cmds()
|
2025-03-19 12:11:26 +03:00
|
|
|
sys.exit(0)
|
2015-04-25 19:39:25 +03:00
|
|
|
|
2023-10-13 09:51:14 +00:00
|
|
|
if cfg.pause:
|
|
|
|
|
set_restore_term_at_exit()
|
2015-01-03 00:14:40 +03:00
|
|
|
|
2024-03-10 14:43:33 +00:00
|
|
|
from mmgen.exception import TestSuiteSpawnedScriptException
|
2025-03-29 09:30:15 +00:00
|
|
|
from test.cmdtest_d.include.runner import CmdTestRunner
|
2022-04-28 11:00:50 +00:00
|
|
|
|
2023-10-13 09:51:14 +00:00
|
|
|
try:
|
2025-03-18 20:09:59 +03:00
|
|
|
tr = CmdTestRunner(cfg, repo_root, data_dir, trash_dir, trash_dir2)
|
2023-10-13 09:51:14 +00:00
|
|
|
tr.run_tests(cmd_args)
|
2025-07-19 10:21:11 +00:00
|
|
|
tr.print_warnings()
|
2024-09-02 09:43:48 +00:00
|
|
|
if tr.daemon_started and not cfg.no_daemon_stop:
|
2025-03-18 11:09:51 +03:00
|
|
|
stop_test_daemons(tr.network_id, remove_datadir=True)
|
2024-08-26 13:47:02 +00:00
|
|
|
if hasattr(tr, 'tg'):
|
|
|
|
|
del tr.tg
|
|
|
|
|
del tr
|
2023-10-13 09:51:14 +00:00
|
|
|
except KeyboardInterrupt:
|
2024-09-02 09:43:48 +00:00
|
|
|
if tr.daemon_started and not cfg.no_daemon_stop:
|
2025-03-18 11:09:51 +03:00
|
|
|
stop_test_daemons(tr.network_id, remove_datadir=True)
|
2025-07-19 10:21:11 +00:00
|
|
|
tr.print_warnings()
|
2024-09-06 12:20:13 +00:00
|
|
|
if hasattr(tr, 'tg'):
|
|
|
|
|
del tr.tg
|
|
|
|
|
del tr
|
2024-10-18 10:32:12 +00:00
|
|
|
die(1, yellow('\ntest.py exiting at user request'))
|
2023-10-13 09:51:14 +00:00
|
|
|
except TestSuiteSpawnedScriptException as e:
|
|
|
|
|
# if spawned script is not running under exec_wrapper, output brief error msg:
|
|
|
|
|
if os.getenv('MMGEN_EXEC_WRAPPER'):
|
|
|
|
|
Msg(red(str(e)))
|
|
|
|
|
Msg(blue('cmdtest.py: spawned script exited with error'))
|
2024-09-20 09:35:58 +00:00
|
|
|
if hasattr(tr, 'tg'):
|
|
|
|
|
del tr.tg
|
|
|
|
|
del tr
|
2024-03-09 11:33:26 +00:00
|
|
|
raise
|
2024-07-27 09:42:44 +00:00
|
|
|
except Exception as e:
|
|
|
|
|
if type(e).__name__ == 'TestSuiteException':
|
|
|
|
|
rmsg('TEST ERROR: ' + str(e))
|
2024-09-20 09:35:58 +00:00
|
|
|
if hasattr(tr, 'tg'):
|
|
|
|
|
del tr.tg
|
|
|
|
|
del tr
|
2023-10-13 09:51:14 +00:00
|
|
|
# if cmdtest.py itself is running under exec_wrapper, re-raise so exec_wrapper can handle exception:
|
|
|
|
|
if os.getenv('MMGEN_EXEC_WRAPPER') or not os.getenv('MMGEN_IGNORE_TEST_PY_EXCEPTION'):
|
|
|
|
|
raise
|
2024-10-18 10:32:12 +00:00
|
|
|
die(1, red('Test script exited with error'))
|