Browse Source

fixes and cleanups throughout

The MMGen Project 3 weeks ago
parent
commit
92fc9fd462

+ 3 - 3
mmgen/main_txcreate.py

@@ -69,10 +69,10 @@ opts_data = {
 			-- -q, --quiet           Suppress warnings; overwrite files without prompting
 			bt -R, --no-rbf          Make transaction non-replaceable (non-replace-by-fee
 			+                        according to BIP 125)
+			-s -s, --swap-proto      Swap protocol to use (Default: {x_dfl},
+			+                        Choices: {x_all})
 			-- -v, --verbose         Produce more verbose output
 			b- -V, --vsize-adj=   f  Adjust transaction's estimated vsize by factor 'f'
-			-s -x, --swap-proto      Swap protocol to use (Default: {x_dfl},
-			+                        Choices: {x_all})
 			-- -y, --yes             Answer 'yes' to prompts, suppress non-essential output
 			e- -X, --cached-balances Use cached balances
 		""",
@@ -101,7 +101,7 @@ opts_data = {
 
 cfg = Config(opts_data=opts_data)
 
-if not cfg.info and len(cfg._args) < {'tx': 1, 'swaptx': 2}[target]:
+if not (cfg.info or cfg.contract_data) and len(cfg._args) < {'tx': 1, 'swaptx': 2}[target]:
 	cfg._usage()
 
 async def main():

+ 3 - 3
mmgen/main_txdo.py

@@ -83,16 +83,16 @@ opts_data = {
 			-- -p, --hash-preset=   p Use the scrypt hash parameters defined by preset 'p'
 			+                         for password hashing (default: '{gc.dfl_hash_preset}')
 			-- -P, --passwd-file=   f Get {pnm} wallet passphrase from file 'f'
+			-- -q, --quiet            Suppress warnings; overwrite files without prompting
 			bt -R, --no-rbf           Make transaction non-replaceable (non-replace-by-fee
 			+                         according to BIP 125)
-			-- -q, --quiet            Suppress warnings; overwrite files without prompting
+			-s -s, --swap-proto       Swap protocol to use (Default: {x_dfl},
+			+                         Choices: {x_all})
 			-- -u, --subseeds=      n The number of subseed pairs to scan for (default: {ss},
 			+                         maximum: {ss_max}). Only the default or first supplied
 			+                         wallet is scanned for subseeds.
 			-- -v, --verbose          Produce more verbose output
 			b- -V, --vsize-adj=     f Adjust transaction's estimated vsize by factor 'f'
-			-s -x, --swap-proto       Swap protocol to use (Default: {x_dfl},
-			+                         Choices: {x_all})
 			e- -X, --cached-balances  Use cached balances
 			-- -y, --yes              Answer 'yes' to prompts, suppress non-essential output
 			-- -z, --show-hash-presets Show information on available hash presets

+ 10 - 4
mmgen/proto/btc/tx/info.py

@@ -14,12 +14,12 @@ proto.btc.tx.info: Bitcoin transaction info class
 
 from ....tx.info import TxInfo
 from ....util import fmt, die
-from ....color import red, green, pink, blue
+from ....color import red, green, blue, pink
 from ....addr import MMGenID
 
 class TxInfo(TxInfo):
 	sort_orders = ('addr', 'raw')
-	txinfo_hdr_fs = 'TRANSACTION DATA\n\nID={i} ({a} {c}) RBF={r} Sig={s} Locktime={l}\n'
+	txinfo_hdr_fs = '{hdr}\n  ID={i} ({a} {c}) RBF={r} Sig={s} Locktime={l}\n'
 	txinfo_hdr_fs_short = 'TX {i} ({a} {c}) RBF={r} Sig={s} Locktime={l}\n'
 	txinfo_ftr_fs = fmt("""
 		Input amount: {i} {d}
@@ -64,7 +64,10 @@ class TxInfo(TxInfo):
 					append_chars=('', ' (chg)')[bool(not is_input and e.is_chg and terse)],
 					append_color='green')
 			else:
-				return MMGenID.fmtc(nonmm_str, width=max_mmwid, color=True)
+				return MMGenID.fmtc(
+					nonmm_str,
+					width = max_mmwid,
+					color = True)
 
 		def format_io(desc):
 			io = getattr(tx, desc)
@@ -134,7 +137,10 @@ class TxInfo(TxInfo):
 			vp1 = 0
 
 		return (
-			'Displaying inputs and outputs in {} sort order'.format({'raw':'raw', 'addr':'address'}[sort])
+			'Inputs/Outputs sort order: {}'.format({
+				'raw':  pink('UNSORTED'),
+				'addr': pink('ADDRESS')
+			}[sort])
 			+ ('\n\n', '\n')[terse]
 			+ ''.join(format_io('inputs'))
 			+ ''.join(format_io('outputs')))

+ 7 - 5
mmgen/proto/btc/tx/new.py

@@ -125,18 +125,19 @@ class New(Base, TxNew):
 	def final_inputs_ok_msg(self, funds_left):
 		return 'Transaction produces {} {} in change'.format(funds_left.hl(), self.coin)
 
-	def check_chg_addr_is_wallet_addr(self):
-		if len([o for o in self.outputs if not o.data]) > 1 and not self.chg_output.mmid:
+	def check_chg_addr_is_wallet_addr(self, message='Change address is not an MMGen wallet address!'):
+		def do_err():
 			from ....ui import confirm_or_raise
 			confirm_or_raise(
 				cfg = self.cfg,
-				message = yellow('Change address is not an MMGen wallet address!'),
+				message = yellow(message),
 				action = 'Are you sure this is what you want?')
+		if len(self.outputs) > 1 and not self.chg_output.mmid:
+			do_err()
 
 	async def create_serialized(self, locktime=None, bump=None):
 
-		if not (bump or self.is_swap):
-			self.inputs.sort_bip69()
+		if not bump:
 			# Set all sequence numbers to the same value, in conformity with the behavior of most modern wallets:
 			do_rbf = self.proto.cap('rbf') and not self.cfg.no_rbf
 			seqnum_val = self.proto.max_int - (2 if do_rbf else 1 if locktime else 0)
@@ -144,6 +145,7 @@ class New(Base, TxNew):
 				i.sequence = seqnum_val
 
 		if not self.is_swap:
+			self.inputs.sort_bip69()
 			self.outputs.sort_bip69()
 
 		inputs_list = [{

+ 1 - 1
mmgen/proto/btc/tx/new_swap.py

@@ -18,6 +18,6 @@ from .new import New
 class NewSwap(New, TxNewSwap):
 	desc = 'Bitcoin swap transaction'
 
-	async def process_swap_cmdline_args(self, cmd_args):
+	async def process_swap_cmdline_args(self, cmd_args, addrfile_args):
 		import sys
 		sys.exit(0)

+ 1 - 1
mmgen/proto/eth/tx/info.py

@@ -18,7 +18,7 @@ from ....color import pink, yellow, blue
 from ....addr import MMGenID
 
 class TxInfo(TxInfo):
-	txinfo_hdr_fs = 'TRANSACTION DATA\n\nID={i} ({a} {c}) Sig={s} Locktime={l}\n'
+	txinfo_hdr_fs = '{hdr}\n  ID={i} ({a} {c}) Sig={s} Locktime={l}\n'
 	txinfo_hdr_fs_short = 'TX {i} ({a} {c}) Sig={s} Locktime={l}\n'
 	txinfo_ftr_fs = fmt("""
 		Total in account:  {i} {d}

+ 7 - 9
mmgen/tx/base.py

@@ -98,8 +98,8 @@ class Base(MMGenObject):
 		tw_copy_attrs = {'scriptPubKey', 'vout', 'amt', 'comment', 'mmid', 'addr', 'confs', 'txid'}
 
 	class Output(MMGenTxIO):
-		is_chg = ListItemAttr(bool, typeconv=False)
-		data   = ListItemAttr(None, typeconv=False) # placeholder
+		is_chg   = ListItemAttr(bool, typeconv=False)
+		data     = ListItemAttr(None, typeconv=False) # placeholder
 
 	class InputList(MMGenTxIOList):
 		desc = 'transaction inputs'
@@ -146,12 +146,10 @@ class Base(MMGenObject):
 			return self.proto.coin_amt('0')
 		return sum(e.amt for e in olist)
 
-	def _chg_output_ops(self, op):
-		is_chgs = [x.is_chg for x in self.outputs]
+	def _chg_output_ops(self, op, attr):
+		is_chgs = [getattr(x, attr) for x in self.outputs]
 		if is_chgs.count(True) == 1:
-			return (
-				is_chgs.index(True) if op == 'idx' else
-				self.outputs[is_chgs.index(True)])
+			return is_chgs.index(True) if op == 'idx' else self.outputs[is_chgs.index(True)]
 		elif is_chgs.count(True) == 0:
 			return None
 		else:
@@ -159,11 +157,11 @@ class Base(MMGenObject):
 
 	@property
 	def chg_idx(self):
-		return self._chg_output_ops('idx')
+		return self._chg_output_ops('idx', 'is_chg')
 
 	@property
 	def chg_output(self):
-		return self._chg_output_ops('output')
+		return self._chg_output_ops('output', 'is_chg')
 
 	def add_timestamp(self):
 		self.timestamp = make_timestamp()

+ 2 - 4
mmgen/tx/file.py

@@ -64,15 +64,13 @@ class MMGenTxFile(MMGenObject):
 		'send_amt': 'skip',
 		'timestamp': None,
 		'blockcount': None,
-		'serialized': None,
-	}
+		'serialized': None}
 	extra_attrs = {
 		'locktime': None,
 		'comment': MMGenTxComment,
 		'coin_txid': CoinTxID,
 		'sent_timestamp': None,
-		'is_swap': False,
-	}
+		'is_swap': None}
 
 	def __init__(self, tx):
 		self.tx       = tx

+ 7 - 5
mmgen/tx/info.py

@@ -15,7 +15,7 @@ tx.info: transaction info class
 import importlib
 
 from ..cfg import gc
-from ..color import red, green, orange
+from ..color import red, green, cyan, orange
 from ..util import msg, msg_r, decode_timestamp, make_timestr
 from ..util2 import format_elapsed_hr
 
@@ -51,6 +51,7 @@ class TxInfo:
 
 		def gen_view():
 			yield (self.txinfo_hdr_fs_short if terse else self.txinfo_hdr_fs).format(
+				hdr = cyan('TRANSACTION DATA'),
 				i = tx.txid.hl(),
 				a = tx.send_amt.hl(),
 				c = tx.dcoin,
@@ -63,19 +64,19 @@ class TxInfo:
 			for attr, label in [('timestamp', 'Created:'), ('sent_timestamp', 'Sent:')]:
 				if (val := getattr(tx, attr)) is not None:
 					_ = decode_timestamp(val)
-					yield f'{label:8} {make_timestr(_)} ({format_elapsed_hr(_)})\n'
+					yield f'  {label:8} {make_timestr(_)} ({format_elapsed_hr(_)})\n'
 
 			if tx.chain != 'mainnet': # if mainnet has a coin-specific name, display it
-				yield green(f'Chain: {tx.chain.upper()}') + '\n'
+				yield green(f'  Chain: {tx.chain.upper()}') + '\n'
 
 			if tx.coin_txid:
-				yield f'{tx.coin} TxID: {tx.coin_txid.hl()}\n'
+				yield f'  {tx.coin} TxID: {tx.coin_txid.hl()}\n'
 
 			enl = ('\n', '')[bool(terse)]
 			yield enl
 
 			if tx.comment:
-				yield f'Comment: {tx.comment.hl()}\n{enl}'
+				yield f'  Comment: {tx.comment.hl()}\n{enl}'
 
 			yield self.format_body(
 				blockcount,
@@ -124,6 +125,7 @@ class TxInfo:
 			from ..ui import do_pager
 			do_pager(o)
 		else:
+			msg('')
 			msg_r(o)
 			from ..term import get_char
 			if pause:

+ 1 - 1
mmgen/tx/new_swap.py

@@ -18,5 +18,5 @@ class NewSwap(New):
 	desc = 'swap transaction'
 	is_swap = True
 
-	async def process_swap_cmdline_args(self, cmd_args):
+	async def process_swap_cmdline_args(self, cmd_args, addrfile_args):
 		raise NotImplementedError(f'Swap not implemented for protocol {self.proto.__name__}')

+ 2 - 2
mmgen/util2.py

@@ -135,14 +135,14 @@ def format_elapsed_days_hr(t, now=None, cached={}):
 		cached[e] = f'{days} day{suf(days)} ' + ('ago' if e > 0 else 'in the future')
 	return cached[e]
 
-def format_elapsed_hr(t, now=None, cached={}, rel_now=True, show_secs=False):
+def format_elapsed_hr(t, now=None, cached={}, rel_now=True, show_secs=False, future_msg='in the future'):
 	e = int((now or time.time()) - t)
 	key = f'{e}:{rel_now}:{show_secs}'
 	if not key in cached:
 		def add_suffix():
 			return (
 				((' ago'           if rel_now else '') if e > 0 else
-				(' in the future' if rel_now else ' (negative elapsed)'))
+				(f' {future_msg}' if rel_now else ' (negative elapsed)'))
 					if (abs_e if show_secs else abs_e // 60) else
 				('just now' if rel_now else ('0 ' + ('seconds' if show_secs else 'minutes')))
 			)

+ 7 - 14
test/cmdtest_d/ct_regtest.py

@@ -44,8 +44,9 @@ from ..include.common import (
 	cmp_or_die,
 	strip_ansi_escapes,
 	gr_uc,
-	getrandhex
-)
+	getrandhex,
+	make_burn_addr)
+
 from .common import (
 	ok_msg,
 	get_file_with_ext,
@@ -53,8 +54,8 @@ from .common import (
 	tw_comment_lat_cyr_gr,
 	tw_comment_zh,
 	tx_comment_jp,
-	get_env_without_debug_vars
-)
+	get_env_without_debug_vars)
+
 from .ct_base import CmdTestBase
 from .ct_shared import CmdTestShared
 
@@ -161,14 +162,6 @@ rt_data = {
 	}
 }
 
-def make_burn_addr(proto, mmtype='compressed'):
-	from mmgen.tool.coin import tool_cmd
-	return tool_cmd(
-		cfg     = cfg,
-		cmdname = 'pubhash2addr',
-		proto   = proto,
-		mmtype  = mmtype).pubhash2addr('00'*20)
-
 class CmdTestRegtest(CmdTestBase, CmdTestShared):
 	'transacting and tracking wallet operations via regtest mode'
 	networks = ('btc', 'ltc', 'bch')
@@ -1185,9 +1178,9 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
 		txfile = self.get_file_with_ext(ext, delete=False, no_dot=True)
 		return self.user_txbump('bob', self.tmpdir, txfile, rtFee[2], add_args=['--send'])
 
-	def generate(self, num_blocks=1):
+	def generate(self, num_blocks=1, add_opts=[]):
 		int(num_blocks)
-		t = self.spawn('mmgen-regtest', ['generate', str(num_blocks)])
+		t = self.spawn('mmgen-regtest', add_opts + ['generate', str(num_blocks)])
 		t.expect(f'Mined {num_blocks} block')
 		return t
 

+ 8 - 0
test/include/common.py

@@ -350,6 +350,14 @@ def in_nix_environment():
 			return True
 	return False
 
+def make_burn_addr(proto, mmtype='compressed', hexdata=None):
+	from mmgen.tool.coin import tool_cmd
+	return tool_cmd(
+		cfg     = cfg,
+		cmdname = 'pubhash2addr',
+		proto   = proto,
+		mmtype  = mmtype).pubhash2addr(hexdata or '00'*20)
+
 def VirtBlockDevice(img_path, size):
 	if sys.platform == 'linux':
 		return VirtBlockDeviceLinux(img_path, size)

+ 1 - 1
test/test-release.sh

@@ -380,7 +380,7 @@ done
 
 in_nix_environment && parity --help >/dev/null 2>&1 || SKIP_PARITY=1
 
-[ "$MMGEN_DISABLE_COLOR" ] || {
+[ "$MMGEN_DISABLE_COLOR" -o ! -t 1 ] || {
 	RED="\e[31;1m" GREEN="\e[32;1m" YELLOW="\e[33;1m" BLUE="\e[34;1m" MAGENTA="\e[35;1m" CYAN="\e[36;1m"
 	RESET="\e[0m"
 }