Browse Source

comments, whitespace, minor cleanups

The MMGen Project 2 months ago
parent
commit
1f1e0a1186

+ 5 - 3
mmgen/devinit.py

@@ -43,14 +43,15 @@ class MMGenObjectDevTools:
 	pexit = lambda *args, **kwargs: MMGenObject_call('pexit', *args, **kwargs)
 	pexit = lambda *args, **kwargs: MMGenObject_call('pexit', *args, **kwargs)
 	pfmt  = lambda *args, **kwargs: MMGenObject_call('pfmt', *args, **kwargs)
 	pfmt  = lambda *args, **kwargs: MMGenObject_call('pfmt', *args, **kwargs)
 
 
-	# Check that all immutables have been initialized.  Expensive, so do only when testing.
+	# Check that all immutable attrs in ‘valid_attrs’ exist and have been initialized.
+	# Expensive, so do only when testing.
 	def immutable_attr_init_check(self):
 	def immutable_attr_init_check(self):
 
 
 		cls = type(self)
 		cls = type(self)
 
 
 		for attrname in self.valid_attrs:
 		for attrname in self.valid_attrs:
-
-			for o in (cls, cls.__bases__[0]): # assume there's only one base class
+			# existence check:
+			for o in cls.__mro__[:3]: # allow for 2 levels of subclassing
 				if attrname in o.__dict__:
 				if attrname in o.__dict__:
 					attr = o.__dict__[attrname]
 					attr = o.__dict__[attrname]
 					break
 					break
@@ -58,6 +59,7 @@ class MMGenObjectDevTools:
 				from .util import die
 				from .util import die
 				die(4, f'unable to find descriptor {cls.__name__}.{attrname}')
 				die(4, f'unable to find descriptor {cls.__name__}.{attrname}')
 
 
+			# initialization check:
 			if type(attr).__name__ == 'ImmutableAttr' and attrname not in self.__dict__:
 			if type(attr).__name__ == 'ImmutableAttr' and attrname not in self.__dict__:
 				from .util import die
 				from .util import die
 				die(4, f'attribute {attrname!r} of {cls.__name__} has not been initialized in constructor!')
 				die(4, f'attribute {attrname!r} of {cls.__name__} has not been initialized in constructor!')

+ 51 - 38
mmgen/help/help_notes.py

@@ -22,11 +22,12 @@ class help_notes:
 
 
 	def txcreate_args(self):
 	def txcreate_args(self):
 		return (
 		return (
-			'<addr,amt>' if self.proto.base_coin == 'ETH' else
-			'[<addr,amt> ...] <change addr, addrlist ID or addr type>')
+			'[ADDR,AMT ...] ADDR <change addr, addrlist ID or addr type>'
+				if self.proto.base_proto == 'Bitcoin' else
+			'ADDR,AMT')
 
 
 	def account_info_desc(self):
 	def account_info_desc(self):
-		return 'account info' if self.proto.base_coin == 'ETH' else 'unspent outputs'
+		return 'unspent outputs' if self.proto.base_proto == 'Bitcoin' else 'account info'
 
 
 	def fee_spec_letters(self, use_quotes=False):
 	def fee_spec_letters(self, use_quotes=False):
 		cu = self.proto.coin_amt.units
 		cu = self.proto.coin_amt.units
@@ -77,14 +78,20 @@ class help_notes:
 
 
 	def address_types(self):
 	def address_types(self):
 		from ..addr import MMGenAddrType
 		from ..addr import MMGenAddrType
-		return '\n  '.join([
-			"'{}','{:<12} - {}".format(k, v.name + "'", v.desc)
-				for k, v in MMGenAddrType.mmtypes.items()
-		])
+		return """
+ADDRESS TYPES:
+
+  Code Type           Description
+  ---- ----           -----------
+  """ + format('\n  '.join(['‘{}’  {:<12} - {}'.format(k, v.name, v.desc)
+				for k, v in MMGenAddrType.mmtypes.items()]))
 
 
 	def fmt_codes(self):
 	def fmt_codes(self):
 		from ..wallet import format_fmt_codes
 		from ..wallet import format_fmt_codes
-		return '\n  '.join(format_fmt_codes().splitlines())
+		return """
+FMT CODES:
+
+  """ + '\n  '.join(format_fmt_codes().splitlines())
 
 
 	def coin_id(self):
 	def coin_id(self):
 		return self.proto.coin_id
 		return self.proto.coin_id
@@ -147,20 +154,7 @@ seed, the same seed length and hash preset parameters must always be used.
 		addr = t.privhex2addr('bead' * 16)
 		addr = t.privhex2addr('bead' * 16)
 		sample_addr = addr.views[addr.view_pref]
 		sample_addr = addr.views[addr.view_pref]
 
 
-		if self.proto.base_coin == 'ETH':
-			return f"""
-EXAMPLES:
-
-  Send 0.123 {self.proto.coin} to an external {self.proto.name} address:
-
-    $ {gc.prog_name} {sample_addr},0.123
-
-  Send 0.123 {self.proto.coin} to another account in wallet 01ABCDEF:
-
-    $ {gc.prog_name} 01ABCDEF:{mmtype}:7,0.123
-"""
-		else:
-			return f"""
+		return f"""
 EXAMPLES:
 EXAMPLES:
 
 
   Send 0.123 {self.proto.coin} to an external {self.proto.name} address, returning the change to a
   Send 0.123 {self.proto.coin} to an external {self.proto.name} address, returning the change to a
@@ -190,23 +184,47 @@ EXAMPLES:
   address of specified type:
   address of specified type:
 
 
     $ {gc.prog_name} {mmtype}
     $ {gc.prog_name} {mmtype}
+""" if self.proto.base_proto == 'Bitcoin' else f"""
+EXAMPLES:
+
+  Send 0.123 {self.proto.coin} to an external {self.proto.name} address:
+
+    $ {gc.prog_name} {sample_addr},0.123
+
+  Send 0.123 {self.proto.coin} to another account in wallet 01ABCDEF:
+
+    $ {gc.prog_name} 01ABCDEF:{mmtype}:7,0.123
 """
 """
 
 
 	def txcreate(self):
 	def txcreate(self):
-		return f"""
+		outputs_info = (
+			"""
+Outputs are specified in the form ADDRESS,AMOUNT or ADDRESS.  The first form
+creates an output sending the given amount to the given address.  The bare
+address form designates the given address as either the change output or the
+sole output of the transaction (excluding any data output).  Exactly one bare
+address argument is required.
+
+For convenience, the bare address argument may be given as ADDRTYPE_CODE or
+SEED_ID:ADDRTYPE_CODE (see ADDRESS TYPES below). In the first form, the first
+unused address of type ADDRTYPE_CODE for each Seed ID in the tracking wallet
+will be displayed in a menu, with the user prompted to select one.  In the
+second form, the user specifies the Seed ID as well, allowing the script to
+select the transaction’s change output or single output without prompting.
+See EXAMPLES below.
+"""
+		if self.proto.base_proto == 'Bitcoin' else """
+The transaction output is specified in the form ADDRESS,AMOUNT.
+""")
+
+		return """
 The transaction’s outputs are listed on the command line, while its inputs
 The transaction’s outputs are listed on the command line, while its inputs
 are chosen from a list of the wallet’s unspent outputs via an interactive
 are chosen from a list of the wallet’s unspent outputs via an interactive
 menu.  Alternatively, inputs may be specified using the --inputs option.
 menu.  Alternatively, inputs may be specified using the --inputs option.
 
 
-All addresses on the command line can be either {self.proto.name} addresses or MMGen
-IDs in the form <seed ID>:<address type letter>:<index>.
-
-Outputs are specified in the form <address>,<amount>, with the change output
-specified by address only.  Alternatively, the change output may be an
-addrlist ID in the form <seed ID>:<address type letter>, in which case the
-first unused address in the tracking wallet matching the requested ID will
-be automatically selected as the change output.
-
+Addresses on the command line can be either native coin addresses or MMGen
+IDs in the form SEED_ID:ADDRTYPE_CODE:INDEX.
+{oinfo}
 If the transaction fee is not specified on the command line (see FEE
 If the transaction fee is not specified on the command line (see FEE
 SPECIFICATION below), it will be calculated dynamically using network fee
 SPECIFICATION below), it will be calculated dynamically using network fee
 estimation for the default (or user-specified) number of confirmations.
 estimation for the default (or user-specified) number of confirmations.
@@ -214,12 +232,7 @@ If network fee estimation fails, the user will be prompted for a fee.
 
 
 Network-estimated fees will be multiplied by the value of --fee-adjust, if
 Network-estimated fees will be multiplied by the value of --fee-adjust, if
 specified.
 specified.
-
-To send the value of all inputs (minus TX fee) to a single output, specify
-a single address with no amount on the command line.  Alternatively, an
-addrlist ID may be specified, and the address will be chosen automatically
-as described above for the change output.
-"""
+""".format(oinfo=outputs_info)
 
 
 	def txsign(self):
 	def txsign(self):
 		from ..proto.btc.params import mainnet
 		from ..proto.btc.params import mainnet

+ 2 - 5
mmgen/main_addrgen.py

@@ -90,17 +90,14 @@ range(s).
 
 
 {n_addrkey}If available, the libsecp256k1 library will be used for address generation.
 {n_addrkey}If available, the libsecp256k1 library will be used for address generation.
 
 
-ADDRESS TYPES:
-  {n_at}
-
 
 
                       NOTES FOR ALL GENERATOR COMMANDS
                       NOTES FOR ALL GENERATOR COMMANDS
 
 
 {n_sw}{n_pw}{n_bw}
 {n_sw}{n_pw}{n_bw}
 
 
-FMT CODES:
+{n_at}
 
 
-  {n_fmt}
+{n_fmt}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 5 - 8
mmgen/main_msg.py

@@ -126,16 +126,13 @@ export - dump signed MMGen message file to ‘signatures.json’, including only
 The `create` operation takes one or more ADDRESS_SPEC arguments with the
 The `create` operation takes one or more ADDRESS_SPEC arguments with the
 following format:
 following format:
 
 
-    SEED_ID:ADDR_TYPE:ADDR_IDX_SPEC
+    SEED_ID:ADDRTYPE_CODE:ADDR_IDX_SPEC
 
 
-where ADDR_TYPE is an address type letter from the list below, and
-ADDR_IDX_SPEC is a comma-separated list of address indexes or hyphen-
-separated address index ranges.
+where ADDRTYPE_CODE is a one-letter address type code from the list below, and
+ADDR_IDX_SPEC is a comma-separated list of address indexes or hyphen-separated
+address index ranges.
 
 
-
-                                ADDRESS TYPES
-
-  {n_at}
+{n_at}
 
 
 
 
                                     NOTES
                                     NOTES

+ 1 - 3
mmgen/main_passgen.py

@@ -110,9 +110,7 @@ EXAMPLES:
 
 
 {n_bw}
 {n_bw}
 
 
-FMT CODES:
-
-  {n_fmt}
+{n_fmt}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 1 - 3
mmgen/main_seedjoin.py

@@ -73,9 +73,7 @@ For usage examples, see the help screen for the 'mmgen-seedsplit' command.
 
 
 {n_pw}
 {n_pw}
 
 
-FMT CODES:
-
-  {f}
+{f}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 1 - 3
mmgen/main_txbump.py

@@ -84,9 +84,7 @@ opts_data = {
 Seed source files must have the canonical extensions listed in the 'FileExt'
 Seed source files must have the canonical extensions listed in the 'FileExt'
 column below:
 column below:
 
 
-FMT CODES:
-
-  {f}
+{f}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 3 - 2
mmgen/main_txcreate.py

@@ -66,7 +66,7 @@ opts_data = {
 			-- -y, --yes             Answer 'yes' to prompts, suppress non-essential output
 			-- -y, --yes             Answer 'yes' to prompts, suppress non-essential output
 			e- -X, --cached-balances Use cached balances
 			e- -X, --cached-balances Use cached balances
 		""",
 		""",
-		'notes': '\n{c}\n{F}\n{x}',
+		'notes': '\n{c}\n{n_at}\n\n{F}\n{x}',
 	},
 	},
 	'code': {
 	'code': {
 		'usage': lambda cfg, proto, help_notes, s: s.format(
 		'usage': lambda cfg, proto, help_notes, s: s.format(
@@ -82,7 +82,8 @@ opts_data = {
 		'notes': lambda cfg, help_notes, s: s.format(
 		'notes': lambda cfg, help_notes, s: s.format(
 			c      = help_notes('txcreate'),
 			c      = help_notes('txcreate'),
 			F      = help_notes('fee'),
 			F      = help_notes('fee'),
-			x      = help_notes('txcreate_examples'))
+			x      = help_notes('txcreate_examples'),
+			n_at   = help_notes('address_types'))
 	}
 	}
 }
 }
 
 

+ 3 - 2
mmgen/main_txdo.py

@@ -95,9 +95,9 @@ opts_data = {
 Seed source files must have the canonical extensions listed in the 'FileExt'
 Seed source files must have the canonical extensions listed in the 'FileExt'
 column below:
 column below:
 
 
-FMT CODES:
+{n_at}
 
 
-  {f}
+{f}
 
 
 {x}"""
 {x}"""
 	},
 	},
@@ -124,6 +124,7 @@ FMT CODES:
 			c       = help_notes('txcreate'),
 			c       = help_notes('txcreate'),
 			F       = help_notes('fee'),
 			F       = help_notes('fee'),
 			s       = help_notes('txsign'),
 			s       = help_notes('txsign'),
+			n_at    = help_notes('address_types'),
 			f       = help_notes('fmt_codes'),
 			f       = help_notes('fmt_codes'),
 			x       = help_notes('txcreate_examples')),
 			x       = help_notes('txcreate_examples')),
 	}
 	}

+ 1 - 3
mmgen/main_txsign.py

@@ -74,9 +74,7 @@ opts_data = {
 Seed source files must have the canonical extensions listed in the 'FileExt'
 Seed source files must have the canonical extensions listed in the 'FileExt'
 column below:
 column below:
 
 
-FMT CODES:
-
-  {f}
+{f}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 1 - 3
mmgen/main_wallet.py

@@ -122,9 +122,7 @@ opts_data = {
 
 
 {n_ss}{n_sw}{n_pw}{n_bw}
 {n_ss}{n_sw}{n_pw}{n_bw}
 
 
-FMT CODES:
-
-  {f}
+{f}
 """
 """
 	},
 	},
 	'code': {
 	'code': {

+ 2 - 3
mmgen/obj.py

@@ -107,10 +107,9 @@ class ImmutableAttr: # Descriptor
 		self.typeconv = typeconv
 		self.typeconv = typeconv
 
 
 		assert isinstance(dtype, self.ok_dtypes), 'ImmutableAttr_check1'
 		assert isinstance(dtype, self.ok_dtypes), 'ImmutableAttr_check1'
-		if include_proto:
-			assert typeconv, 'ImmutableAttr_check2'
+
 		if set_none_ok:
 		if set_none_ok:
-			assert typeconv and not isinstance(dtype, str), 'ImmutableAttr_check3'
+			assert typeconv and not isinstance(dtype, str), 'ImmutableAttr_check2'
 
 
 		if typeconv:
 		if typeconv:
 			# convert this attribute's type
 			# convert this attribute's type

+ 1 - 2
mmgen/rpc.py

@@ -21,7 +21,6 @@ rpc: Cryptocoin RPC library for the MMGen suite
 """
 """
 
 
 import sys, re, base64, json, asyncio, importlib
 import sys, re, base64, json, asyncio, importlib
-from decimal import Decimal
 from collections import namedtuple
 from collections import namedtuple
 
 
 from .util import msg, ymsg, die, fmt, fmt_list, pp_fmt, oneshot_warning
 from .util import msg, ymsg, die, fmt, fmt_list, pp_fmt, oneshot_warning
@@ -75,7 +74,7 @@ class IPPort(HiliteStr, InitErrors):
 
 
 class json_encoder(json.JSONEncoder):
 class json_encoder(json.JSONEncoder):
 	def default(self, o):
 	def default(self, o):
-		if isinstance(o, Decimal):
+		if type(o).__name__.endswith('Amt'):
 			return str(o)
 			return str(o)
 		else:
 		else:
 			return json.JSONEncoder.default(self, o)
 			return json.JSONEncoder.default(self, o)

+ 2 - 1
test/cmdtest_d/ct_regtest.py

@@ -63,7 +63,8 @@ pat_date_time = r'\b\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d\b'
 
 
 dfl_wcls = get_wallet_cls('mmgen')
 dfl_wcls = get_wallet_cls('mmgen')
 
 
-tx_fee = rtFundAmt = rtFee = rtBals = rtBals_gb = rtBobOp3 = rtAmts = {} # ruff
+tx_fee = rtFundAmt = rtFee = rtBals = rtBals_gb = rtBobOp3 = rtAmts = None # ruff
+
 rt_pw = 'abc-α'
 rt_pw = 'abc-α'
 rt_data = {
 rt_data = {
 	'tx_fee': {'btc':'0.0001', 'bch':'0.001', 'ltc':'0.01'},
 	'tx_fee': {'btc':'0.0001', 'bch':'0.001', 'ltc':'0.01'},

+ 1 - 1
test/include/pexpect.py

@@ -82,7 +82,7 @@ class MMGenPexpect:
 
 
 	def view_tx(self, view):
 	def view_tx(self, view):
 		self.expect(r'View.* transaction.*\? .*: ', view, regex=True)
 		self.expect(r'View.* transaction.*\? .*: ', view, regex=True)
-		if view not in 'n\n':
+		if view not in 'vn\n':
 			self.expect('to continue: ', '\n')
 			self.expect('to continue: ', '\n')
 
 
 	def do_comment(self, add_comment, has_label=False):
 	def do_comment(self, add_comment, has_label=False):