Browse Source

fixes and cleanups throughout

The MMGen Project 2 weeks ago
parent
commit
7b6717d85a

+ 5 - 13
mmgen/main_txbump.py

@@ -164,34 +164,26 @@ async def main():
 		kal = kl = sign_and_send = None
 	else:
 		orig_tx = await CompletedTX(cfg=cfg, filename=tx_file)
+		kal = get_keyaddrlist(cfg, orig_tx.proto)
+		kl = get_keylist(cfg)
+		sign_and_send = any([seed_files, kl, kal])
 
 	if not silent:
 		msg(green('ORIGINAL TRANSACTION'))
 		msg(orig_tx.info.format(terse=True))
 
-	if not cfg.autosign:
-		kal = get_keyaddrlist(cfg, orig_tx.proto)
-		kl = get_keylist(cfg)
-		sign_and_send = any([seed_files, kl, kal])
-
 	from .tw.ctl import TwCtl
 	tx = await BumpTX(
 		cfg  = cfg,
 		data = orig_tx.__dict__,
 		automount = cfg.autosign,
 		check_sent = cfg.autosign or sign_and_send,
+		new_outputs = bool(cfg._args),
 		twctl = await TwCtl(cfg, orig_tx.proto) if orig_tx.proto.tokensym else None)
 
-	tx.orig_rel_fee = tx.get_orig_rel_fee()
-
-	if cfg._args:
-		tx.new_outputs = True
-		tx.is_swap = False
-		tx.outputs = tx.OutputList(tx)
-		tx.cfg = cfg # NB: with --automount, must use current cfg opts, not those from orig_tx
+	if tx.new_outputs:
 		await tx.create(cfg._args, caller='txdo' if sign_and_send else 'txcreate')
 	else:
-		tx.new_outputs = False
 		await tx.create_feebump(silent=silent)
 
 	if not silent:

+ 2 - 2
mmgen/proto/eth/tx/bump.py

@@ -21,8 +21,8 @@ from .new import New, TokenNew
 class Bump(Completed, New, TxBase.Bump):
 	desc = 'fee-bumped transaction'
 
-	def get_orig_rel_fee(self): # disable this check for ETH
-		return 0
+	def get_orig_rel_fee(self):
+		return self.txobj['gasPrice'].to_unit('Gwei')
 
 	@property
 	def min_fee(self):

+ 20 - 3
mmgen/tx/bump.py

@@ -15,16 +15,29 @@ tx.bump: transaction bump class
 from .new import New
 from .completed import Completed
 from ..util import msg, ymsg, is_int, die
+from ..color import pink
 
 class Bump(Completed, New):
 	desc = 'fee-bumped transaction'
 	ext  = 'rawtx'
 	bump_output_idx = None
 	is_bump = True
+	swap_attrs = ('is_swap',)
 
-	def __init__(self, check_sent, *args, **kwargs):
+	def __init__(self, *, check_sent, new_outputs, **kwargs):
 
-		super().__init__(*args, **kwargs)
+		super().__init__(**kwargs)
+
+		self.new_outputs = new_outputs
+		self.orig_rel_fee = self.get_orig_rel_fee()
+
+		if new_outputs:
+			from .base import Base
+			if self.is_swap:
+				for attr in self.swap_attrs:
+					setattr(self, attr, getattr(Base, attr))
+			self.outputs = self.OutputList(self)
+			self.cfg = kwargs['cfg'] # must use current cfg opts, not those from orig_tx
 
 		if not self.is_replaceable():
 			die(1, f'Transaction {self.txid} is not replaceable')
@@ -60,7 +73,11 @@ class Bump(Completed, New):
 		output_idx = self.choose_output()
 
 		if not silent:
-			msg(f'Minimum fee for new transaction: {self.min_fee.hl()} {self.proto.coin}')
+			msg('Minimum fee for new transaction: {} {} ({} {})'.format(
+				self.min_fee.hl(),
+				self.proto.coin,
+				pink(self.fee_abs2rel(self.min_fee)),
+				self.rel_fee_disp))
 
 		self.usr_fee = self.get_usr_fee_interactive(fee=self.cfg.fee, desc='User-selected')
 

+ 20 - 11
mmgen/tx/new.py

@@ -83,7 +83,9 @@ class New(Base):
 	_funds_available = namedtuple('funds_available', ['is_positive', 'amt'])
 
 	def __init__(self, *args, target=None, **kwargs):
-		self.is_swap = target == 'swaptx'
+		if target == 'swaptx':
+			self.is_swap = True
+			self.swap_proto = kwargs['cfg'].swap_proto
 		super().__init__(*args, **kwargs)
 
 	def warn_insufficient_funds(self, amt, coin):
@@ -183,6 +185,8 @@ class New(Base):
 
 		arg, amt = arg_in.split(',', 1) if ',' in arg_in else (arg_in, None)
 
+		coin_addr, mmid = (None, None)
+
 		if mmid := get_obj(MMGenID, proto=proto, id_str=arg, silent=True):
 			coin_addr = mmaddr2coinaddr(self.cfg, arg, ad_w, ad_f, proto)
 		elif is_coin_addr(proto, arg):
@@ -191,7 +195,6 @@ class New(Base):
 			if proto.base_proto_coin != 'BTC':
 				die(2, f'Change addresses not supported for {proto.name} protocol')
 			self.chg_autoselected = True
-			coin_addr = None
 		else:
 			die(2, f'{arg_in}: invalid command-line argument')
 
@@ -219,7 +222,7 @@ class New(Base):
 
 		parsed_args = [self.parse_cmdline_arg(self.proto, arg, ad_f, ad_w) for arg in cmd_args]
 
-		chg_args = [a for a in parsed_args if not ((a.amt and a.addr) or a.data)]
+		chg_args = [a for a in parsed_args if not (a.amt or a.data)]
 
 		if len(chg_args) > 1:
 			desc = 'requested' if self.chg_autoselected else 'listed'
@@ -229,13 +232,15 @@ class New(Base):
 			if a.data:
 				self.add_output(None, self.proto.coin_amt('0'), data=a.data)
 			else:
-				exclude = [a.mmid for a in parsed_args if a.mmid]
 				self.add_output(
 					coinaddr = a.addr or (
-						await self.get_autochg_addr(self.proto, a.arg, exclude=exclude, desc='change address')
-					).addr,
-					amt      = self.proto.coin_amt(a.amt or '0'),
-					is_chg   = not a.amt)
+						await self.get_autochg_addr(
+							self.proto,
+							a.arg,
+							exclude = [a.mmid for a in parsed_args if a.mmid],
+							desc = 'change address')).addr,
+					amt = self.proto.coin_amt(a.amt or '0'),
+					is_chg = not a.amt)
 
 		if self.chg_idx is None:
 			die(2,
@@ -387,13 +392,14 @@ class New(Base):
 				sel_unspent,
 				outputs_sum):
 			return False
+
 		self.copy_inputs_from_tw(sel_unspent)  # makes self.inputs
 		return True
 
-	async def get_fee(self, fee, outputs_sum):
+	async def get_fee(self, fee, outputs_sum, start_fee_desc):
 
 		if fee:
-			self.usr_fee = self.get_usr_fee_interactive(fee, 'User-selected')
+			self.usr_fee = self.get_usr_fee_interactive(fee, start_fee_desc)
 		else:
 			fee_per_kb, fe_type = await self.get_rel_fee_from_network()
 			self.usr_fee = self.get_usr_fee_interactive(
@@ -468,7 +474,10 @@ class New(Base):
 			fee_hint = None
 			if self.is_swap:
 				fee_hint = self.update_vault_output(self.vault_output.amt or self.sum_inputs())
-			if funds_left := await self.get_fee(fee_hint or self.cfg.fee, outputs_sum):
+			if funds_left := await self.get_fee(
+					self.cfg.fee or fee_hint,
+					outputs_sum,
+					'User-selected' if self.cfg.fee else 'Recommended' if fee_hint else None):
 				break
 
 		self.check_non_mmgen_inputs(caller)

+ 12 - 10
scripts/exec_wrapper.py

@@ -123,6 +123,15 @@ def exec_wrapper_tracemalloc_log():
 			s = sum(stat.size for stat in stats) / 1024,
 			w = col1w))
 
+def exec_wrapper_do_exit(e, exit_val):
+	if exit_val != 0:
+		exec_wrapper_write_traceback(e, exit_val)
+	else:
+		if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
+			exec_wrapper_tracemalloc_log()
+		exec_wrapper_end_msg()
+	exec_wrapper_sys.exit(exit_val)
+
 import sys as exec_wrapper_sys
 import os as exec_wrapper_os
 import time as exec_wrapper_time
@@ -145,17 +154,10 @@ try:
 	with open(exec_wrapper_execed_file) as fp:
 		exec(fp.read())
 except SystemExit as e:
-	if e.code != 0:
-		exec_wrapper_write_traceback(e, e.code)
-	else:
-		if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
-			exec_wrapper_tracemalloc_log()
-		exec_wrapper_end_msg()
-	exec_wrapper_sys.exit(e.code)
+	exec_wrapper_do_exit(e, e.code)
 except Exception as e:
-	exit_val = e.mmcode if hasattr(e, 'mmcode') else e.code if hasattr(e, 'code') else 1
-	exec_wrapper_write_traceback(e, exit_val)
-	exec_wrapper_sys.exit(exit_val)
+	exec_wrapper_do_exit(
+		e, e.mmcode if hasattr(e, 'mmcode') else e.code if hasattr(e, 'code') else 1)
 
 if exec_wrapper_os.getenv('MMGEN_TRACEMALLOC'):
 	exec_wrapper_tracemalloc_log()

+ 3 - 2
test/cmdtest.py

@@ -447,7 +447,7 @@ class CmdGroupMgr:
 				yield '  {} - {}'.format(
 					yellow(name.ljust(13)),
 					(cls.__doc__.strip() if cls.__doc__ else cls.__name__))
-				if hasattr(cls, 'cmd_subgroups'):
+				if 'cmd_subgroups' in cls.__dict__:
 					subgroups = {k:v for k, v in cls.cmd_subgroups.items() if not k.startswith('_')}
 					max_w = max(len(k) for k in subgroups)
 					for k, v in subgroups.items():
@@ -762,7 +762,8 @@ class CmdTestRunner:
 									if isinstance(e, KeyError) and e.args[0] == cmdname:
 										ret = getattr(self.tg, cmdname)()
 										if type(ret).__name__ == 'coroutine':
-											asyncio.run(ret)
+											ret = asyncio.run(ret)
+										self.process_retval(cmdname, ret)
 									else:
 										raise
 								do_between()

+ 4 - 3
test/cmdtest_d/ct_automount.py

@@ -14,14 +14,15 @@ test.cmdtest_d.ct_automount: autosigning with automount tests for the cmdtest.py
 import time
 
 from .ct_autosign import CmdTestAutosignThreaded
-from .ct_regtest import CmdTestRegtestBDBWallet, rt_pw
+from .ct_regtest import CmdTestRegtest, rt_pw
 from ..include.common import cfg, gr_uc
 
-class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet):
+class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtest):
 	'automounted transacting operations via regtest mode'
 
 	networks = ('btc', 'bch', 'ltc')
 	tmpdir_nums = [49]
+	bdb_wallet = True
 
 	rt_data = {
 		'rtFundAmt': {'btc':'500', 'bch':'500', 'ltc':'5500'},
@@ -78,7 +79,7 @@ class CmdTestAutosignAutomount(CmdTestAutosignThreaded, CmdTestRegtestBDBWallet)
 		self.coins = [cfg.coin.lower()]
 
 		CmdTestAutosignThreaded.__init__(self, trunner, cfgs, spawn)
-		CmdTestRegtestBDBWallet.__init__(self, trunner, cfgs, spawn)
+		CmdTestRegtest.__init__(self, trunner, cfgs, spawn)
 
 		if trunner is None:
 			return

+ 7 - 4
test/cmdtest_d/ct_autosign.py

@@ -441,19 +441,22 @@ class CmdTestAutosignThreaded(CmdTestAutosignBase):
 	no_insert_check = False
 	threaded        = True
 
-	def _wait_loop_start(self):
+	def _wait_loop_start(self, add_opts=[]):
 		t = self.spawn(
 			'mmgen-autosign',
-			self.opts + ['--full-summary', 'wait'],
+			self.opts + add_opts + ['--full-summary', 'wait'],
 			direct_exec      = True,
 			no_passthru_opts = True,
 			spawn_env_override = self.spawn_env | {'EXEC_WRAPPER_DO_RUNTIME_MSG': ''})
 		self.write_to_tmpfile('autosign_thread_pid', str(t.ep.pid))
 		return t
 
-	def wait_loop_start(self):
+	def wait_loop_start(self, add_opts=[]):
 		import threading
-		threading.Thread(target=self._wait_loop_start, name='Autosign wait loop').start()
+		threading.Thread(
+			target = self._wait_loop_start,
+			kwargs = {'add_opts': add_opts},
+			name   = 'Autosign wait loop').start()
 		time.sleep(0.1) # try to ensure test output is displayed before next test starts
 		return 'silent'
 

+ 4 - 3
test/cmdtest_d/ct_regtest.py

@@ -280,8 +280,8 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
 		('bob_split1',                 'splitting Bob’s funds'),
 		('generate',                   'mining a block'),
 		('bob_bal2',                   'Bob’s balance'),
-		('bob_rbf_1output_create',     'creating RBF tx with one output'),
-		('bob_rbf_1output_bump',       'bumping RBF tx with one output'),
+		('bob_rbf_1output_create',     'creating RBF TX with one output'),
+		('bob_rbf_1output_bump',       'creating replacement TX with one output'),
 		('bob_bal2a',                  'Bob’s balance (age_fmt=confs)'),
 		('bob_bal2b',                  'Bob’s balance (showempty=1)'),
 		('bob_bal2c',                  'Bob’s balance (showempty=1 minconf=2 age_fmt=days)'),
@@ -1122,7 +1122,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
 			one_output = True)
 
 	def bob_send_maybe_rbf(self):
-		outputs_cl = self._create_tx_outputs('alice', (('L', 1, ', 60'), ('C', 1, ', 40')))
+		outputs_cl = self._create_tx_outputs('alice', (('L', 1, ',60'), ('C', 1, ',40')))
 		outputs_cl += [self._user_sid('bob')+':'+rtBobOp3]
 		return self.user_txdo(
 			user               = 'bob',
@@ -2174,4 +2174,5 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
 		return 'ok'
 
 class CmdTestRegtestBDBWallet(CmdTestRegtest):
+	'transacting and tracking wallet operations via regtest mode (legacy BDB wallet)'
 	bdb_wallet = True

+ 1 - 8
test/cmdtest_d/ct_swap.py

@@ -13,15 +13,8 @@ test.cmdtest_d.ct_swap: asset swap tests for the cmdtest.py test suite
 """
 
 from mmgen.protocol import init_proto
-
 from ..include.common import gr_uc
-
-from .ct_regtest import (
-	CmdTestRegtest,
-	rt_data,
-	dfl_wcls,
-	rt_pw,
-	cfg)
+from .ct_regtest import CmdTestRegtest, rt_data, dfl_wcls, rt_pw, cfg
 
 sample1 = gr_uc[:24]
 sample2 = '00010203040506'

+ 1 - 3
test/test-release.sh

@@ -217,9 +217,7 @@ do_reexec() {
 
 install_secp256k1_mod_maybe() {
 	if [[ "$repo" =~ ^mmgen[-_]wallet ]]; then
-		[ -e mmgen/proto/secp256k1/secp256k1*$(python3 --version | sed 's/.* //;s/\.//;s/\..*//')* ] || {
-			eval "python3 setup.py build_ext --inplace $STDOUT_DEVNULL"
-		}
+		eval "python3 setup.py build_ext --inplace $STDOUT_DEVNULL"
 	fi
 }