Browse Source

mmgen-tool txview: add 'sort' option, rename old sort option to 'filesort'

- filesort: sort tx files by time ('mtime', 'ctime', 'atime')
- sort: view transaction inputs and outputs either sorted by MMGen ID/address
        ('addr') or in their actual order in the transaction ('raw')
MMGen 6 years ago
parent
commit
105f6c3033
3 changed files with 40 additions and 14 deletions
  1. 1 1
      mmgen/altcoins/eth/tx.py
  2. 20 8
      mmgen/tool.py
  3. 19 5
      mmgen/tx.py

+ 1 - 1
mmgen/altcoins/eth/tx.py

@@ -239,7 +239,7 @@ class EthereumMMGenTX(MMGenTX):
 		if self.outputs:
 			self.send_amt = self.outputs[0].amt
 
-	def format_view_body(self,blockcount,nonmm_str,max_mmwid,enl,terse):
+	def format_view_body(self,blockcount,nonmm_str,max_mmwid,enl,terse,sort):
 		m = {}
 		for k in ('in','out'):
 			if len(getattr(self,k+'puts')):

+ 20 - 8
mmgen/tool.py

@@ -519,20 +519,32 @@ class MMGenToolCmdFile(MMGenToolCmdBase):
 		return PasswordList(infile=mmgen_passwdfile).chksum
 
 	def txview( varargs_call_sig = { # hack to allow for multiple filenames
-					'args':   ( 'mmgen_tx_file(s)', 'pager', 'terse', 'sort' ),
-					'dfls':   ( False, False, 'mtime' ),
-					'annots': { 'mmgen_tx_file(s)': str, 'sort': '(valid options: mtime,ctime,atime)' } },
+					'args': (
+						'mmgen_tx_file(s)',
+						'pager',
+						'terse',
+						'sort',
+						'filesort' ),
+					'dfls': ( False, False, 'addr', 'mtime' ),
+					'annots': {
+						'mmgen_tx_file(s)': str,
+						'sort': '(valid options: addr,raw)',
+						'filesort': '(valid options: mtime,ctime,atime)'
+						} },
 				*infiles,**kwargs):
 		"show raw/signed MMGen transaction in human-readable form"
-		self = varargs_call_sig
+
+		terse = bool(kwargs.get('terse'))
+		tx_sort = kwargs.get('sort') or 'addr'
+		file_sort = kwargs.get('filesort') or 'mtime'
+
 		from mmgen.filename import MMGenFileList
-		terse = 'terse' in kwargs and kwargs['terse']
-		sort_key = kwargs['sort'] if 'sort' in kwargs else 'mtime'
 		from mmgen.tx import MMGenTX
 		flist = MMGenFileList(infiles,ftype=MMGenTX)
-		flist.sort_by_age(key=sort_key) # in-place sort
+		flist.sort_by_age(key=file_sort) # in-place sort
+
 		sep = '—'*77+'\n'
-		return sep.join([MMGenTX(fn).format_view(terse=terse) for fn in flist.names()]).rstrip()
+		return sep.join([MMGenTX(fn).format_view(terse=terse,sort=tx_sort) for fn in flist.names()]).rstrip()
 
 class MMGenToolCmdFileCrypt(MMGenToolCmdBase):
 	"""

+ 19 - 5
mmgen/tx.py

@@ -293,6 +293,8 @@ class MMGenTX(MMGenObject):
 	usr_fee_prompt = 'Enter transaction fee: '
 	fee_is_approximate = False
 	fn_fee_unit = 'satoshi'
+	view_sort_orders = ('addr','raw')
+	dfl_view_sort_order = 'addr'
 
 	msg_low_coin = 'Selected outputs insufficient to fund this transaction ({} {} needed)'
 	msg_no_change_output = """
@@ -1035,7 +1037,11 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 	def is_replaceable(self):
 		return self.inputs[0].sequence == g.max_int - 2
 
-	def format_view_body(self,blockcount,nonmm_str,max_mmwid,enl,terse):
+	def format_view_body(self,blockcount,nonmm_str,max_mmwid,enl,terse,sort):
+
+		if sort not in self.view_sort_orders:
+			m = '{!r}: invalid transaction view sort order.  Valid options: {}'
+			die(1,m.format(sort,','.join(self.view_sort_orders)))
 
 		def format_io(desc):
 			io = getattr(self,desc)
@@ -1043,7 +1049,12 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 			out = desc.capitalize() + ':\n' + enl
 			addr_w = max(len(e.addr) for e in io)
 			confs_per_day = 60*60*24 // g.proto.secs_per_block
-			for n,e in enumerate(sorted(io,key=lambda o: o.mmid.sort_key if o.mmid else o.addr)):
+			io_sorted = {
+				# prepend '/' (sorts before '0') to ensure non-MMGen addrs are displayed first
+				'addr': lambda: sorted(io,key=lambda o: o.mmid.sort_key if o.mmid else '/'+o.addr),
+				'raw':  lambda: io
+			}[sort]
+			for n,e in enumerate(io_sorted()):
 				if ip and blockcount:
 					confs = e.confs + blockcount - self.blockcount
 					days = int(confs // confs_per_day)
@@ -1072,7 +1083,10 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 					out += '\n'.join([('{:>3} {:<8} {}'.format(*d)) for d in items if d[2]]) + '\n\n'
 			return out
 
-		return  format_io('inputs') + format_io('outputs')
+		md = {'raw':'raw','addr':'address'}
+		m = 'Displaying inputs and outputs in {} sort order'.format(md[sort])
+
+		return m + ('\n\n','\n')[terse] + format_io('inputs') + format_io('outputs')
 
 	def format_view_rel_fee(self,terse):
 		return ' ({} {})\n'.format(
@@ -1090,7 +1104,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 			out += ', Base {}, Witness {}'.format(ts-ws,ws)
 		return out + '\n'
 
-	def format_view(self,terse=False):
+	def format_view(self,terse=False,sort=dfl_view_sort_order):
 		blockcount = None
 		if g.proto.base_coin != 'ETH':
 			try:
@@ -1127,7 +1141,7 @@ Selected non-{pnm} inputs: {{}}""".strip().format(pnm=g.proj_name,pnl=g.proj_nam
 		if self.label:
 			out += 'Comment: {}\n{}'.format(self.label.hl(),enl)
 
-		out += self.format_view_body(blockcount,nonmm_str,max_mmwid,enl,terse=terse)
+		out += self.format_view_body(blockcount,nonmm_str,max_mmwid,enl,terse=terse,sort=sort)
 
 		out += (self.txview_ftr_fs,self.txview_ftr_fs_short)[bool(terse)].format(
 			i=self.sum_inputs().hl(),