Browse Source

mmnode-blocks-info: -s totals -> -s total; rewrite total stats code

The MMGen Project 4 years ago
parent
commit
cb42dd9207
2 changed files with 67 additions and 21 deletions
  1. 65 21
      mmgen/node_tools/BlocksInfo.py
  2. 2 0
      test/unit_tests_d/nt_BlocksInfo.py

+ 65 - 21
mmgen/node_tools/BlocksInfo.py

@@ -96,14 +96,14 @@ class BlocksInfo:
 	)
 	fs_lsqueeze2 = ('interval',)
 
-	all_stats = ['avg','totals','range','diff']
+	all_stats = ['avg','total','range','diff']
 	dfl_stats = ['range','diff']
 	noindent_stats = ['avg']
 
 	avg_stats_skip = {'block', 'hash', 'date', 'version','miner'}
 	stats_deps = {
 		'avg':    set(fields) - avg_stats_skip,
-		'totals': {'interval','subsidy','totalfee','nTx','inputs','outputs','utxo_inc'},
+		'total':  {'interval','subsidy','totalfee','nTx','inputs','outputs','utxo_inc'},
 		'range':  {},
 		'diff':   {},
 	}
@@ -424,7 +424,8 @@ class BlocksInfo:
 		yield self.fs.format(*hdr2)
 
 	def process_stats(self,sname):
-		return self.output_stats(getattr(self,f'create_{sname}_stats')(),sname)
+		method = getattr(self,f'create_{sname}_stats',None)
+		return self.output_stats(method() if method else self.create_stats(sname),sname)
 
 	def fmt_stat_item(self,fs,s):
 		return fs.format(s) if type(fs) == str else fs(s)
@@ -535,25 +536,68 @@ class BlocksInfo:
 		fs = ''.join(self.gen_fs(self.fnames,fill=self.avg_stats_skip,add_name=True)).strip()
 		return ('averages', ('Averages:', (fs, dict(gen())) ))
 
-	async def create_totals_stats(self):
+	def total_stats_data(self,data,spec_conv,spec_val):
 		coin = self.rpc.proto.coin
-		fields = {
-			'interval': ('Solve Time:    {} h/m/s', secs_to_dhms),
-			'subsidy':  ('Subsidy:       {} %s' % coin, self.fmt_funcs['su']),
-			'totalfee': ('Fees:          {} %s' % coin, self.fmt_funcs['tf']),
-			'earnings': ('Subsidy+Fees:  {} %s' % coin, self.fmt_funcs['tf']),
-			'nTx':      ('nTx:           {}', int),
-			'inputs':   ('Inputs:        {}', int),
-			'outputs':  ('Outputs:       {}', int),
-			'utxo_inc': ('UTXO change:  {:<+}', int),
-		}
-		fnames = list( set(fields) & set(self.fnames) )
-		vals = dict( ( name, sum(getattr(blk,name) for blk in self.res) ) for name in fnames )
-		if 'subsidy' in vals and 'totalfee' in vals:
-			vals['earnings'] = vals['subsidy'] + vals['totalfee']
-			fnames.append('earnings')
-		res = [( v[0], k, v[1], vals[k] ) for k,v in fields.items() if k in fnames]
-		return ( 'totals', ['Totals:'] + res )
+		return data(
+			hdr = 'Totals for processed blocks:',
+			func = lambda field: sum(getattr(block,field) for block in self.res),
+			spec_sufs = { 'subsidy': f' {coin}', 'totalfee': f' {coin}', 'reward': f' {coin}' },
+			spec_convs = {
+				'interval': spec_conv(0,  lambda arg: secs_to_dhms(arg)),
+				'utxo_inc': spec_conv(-1, '{:<+}'),
+				'reward':   spec_conv(0,  self.fmt_funcs['tf']),
+			},
+			spec_vals = (
+				spec_val(
+					'reward', 'Reward', 'totalfee',
+					lambda values: {'subsidy','totalfee'} <= set(values),
+					lambda values: values['subsidy'] + values['totalfee']
+				),
+			)
+		)
+
+	async def create_stats(self,sname):
+
+		def convert_stats_hdr(field):
+			v = self.fields[field]
+			return '{} {}'.format(v.hdr1.strip(), v.hdr2.strip()).replace('- ','') if v.hdr1 else v.hdr2.strip()
+
+		d = getattr(self,f'{sname}_stats_data')(
+			namedtuple('stats_data',['hdr','func','spec_sufs','spec_convs','spec_vals']),
+			namedtuple('spec_conv',['width_adj','conv']),
+			namedtuple('spec_val',['name','lbl','insert_after','condition','code'])
+		)
+
+		fnames = [n for n in self.fnames if n in self.stats_deps[sname]]
+		lbls   = {n:convert_stats_hdr(n) for n in fnames}
+		values = {n:d.func(n) for n in fnames}
+		col1_w = max((len(l) for l in lbls.values()),default=0) + 2
+
+		for v in d.spec_vals:
+			if v.condition(values):
+				try:    idx = fnames.index(v.insert_after) + 1
+				except: idx = 0
+				fnames.insert(idx,v.name)
+				lbls[v.name] = v.lbl
+				values[v.name] = v.code(values)
+
+		def gen():
+			for n,fname in enumerate(fnames):
+				spec_conv = d.spec_convs.get(fname)
+				yield (
+					'{lbl:{wid}} {{}}{suf}'.format(
+						lbl = lbls[fname] + ':',
+						wid = col1_w + (spec_conv.width_adj if spec_conv else 0),
+						suf = d.spec_sufs.get(fname) or ''
+					),
+					fname,
+					spec_conv.conv if spec_conv else (
+						(lambda x: self.fmt_funcs[x] if x else '{}')(self.fields[fname].fmt_func)
+					),
+					values[fname]
+				)
+
+		return ( sname, (d.hdr,) + tuple(gen()) )
 
 	def process_stats_pre(self,i):
 		if (self.fnames and not self.opt.stats_only) or i != 0:

+ 2 - 0
test/unit_tests_d/nt_BlocksInfo.py

@@ -52,6 +52,8 @@ class dummyOpt:
 	fields = None
 	stats = None
 	miner_info = None
+	header_info = None
+	full_stats = None
 
 class unit_tests: