Browse Source

whitespace, minor changes (16 files)

The MMGen Project 2 months ago
parent
commit
0b79ef719b

+ 188 - 212
mmgen_node_tools/BlocksInfo.py

@@ -20,58 +20,57 @@
 mmgen_node_tools.BlocksInfo: Display information about a block or range of blocks
 mmgen_node_tools.BlocksInfo: Display information about a block or range of blocks
 """
 """
 
 
-import re,json
+import re, json
 from collections import namedtuple
 from collections import namedtuple
-from time import strftime,gmtime
+from time import strftime, gmtime
 from decimal import Decimal
 from decimal import Decimal
 
 
-from mmgen.util import msg,Msg,Msg_r,die,suf,secs_to_ms,secs_to_dhms,is_int
+from mmgen.util import msg, Msg, Msg_r, die, suf, secs_to_ms, secs_to_dhms, is_int
 from mmgen.rpc.util import json_encoder
 from mmgen.rpc.util import json_encoder
 
 
 class RangeParser:
 class RangeParser:
 
 
 	debug = False
 	debug = False
 
 
-	def __init__(self,caller,arg):
+	def __init__(self, caller, arg):
 		self.caller = caller
 		self.caller = caller
 		self.arg = self.orig_arg = arg
 		self.arg = self.orig_arg = arg
 
 
-	def parse(self,target):
-		ret = getattr(self,'parse_'+target)()
+	def parse(self, target):
+		ret = getattr(self, 'parse_'+target)()
 		if self.debug:
 		if self.debug:
 			msg(f'arg after parse({target}): {self.arg}')
 			msg(f'arg after parse({target}): {self.arg}')
 		return ret
 		return ret
 
 
 	def finalize(self):
 	def finalize(self):
 		if self.arg:
 		if self.arg:
-			die(1,f'{self.orig_arg!r}: invalid range specifier')
+			die(1, f'{self.orig_arg!r}: invalid range specifier')
 
 
 	def parse_from_tip(self):
 	def parse_from_tip(self):
-		m = re.match(r'-([0-9]+)(.*)',self.arg)
+		m = re.match(r'-([0-9]+)(.*)', self.arg)
 		if m:
 		if m:
-			res,self.arg = (m[1],m[2])
+			res, self.arg = (m[1], m[2])
 			return self.caller.check_nblocks(int(res))
 			return self.caller.check_nblocks(int(res))
 
 
 	def parse_abs_range(self):
 	def parse_abs_range(self):
-		m = re.match(r'([^+-]+)(-([^+-]+)){0,1}(.*)',self.arg)
+		m = re.match(r'([^+-]+)(-([^+-]+)){0,1}(.*)', self.arg)
 		if m:
 		if m:
 			if self.debug:
 			if self.debug:
 				msg(f'abs_range parse: first={m[1]}, last={m[3]}')
 				msg(f'abs_range parse: first={m[1]}, last={m[3]}')
 			self.arg = m[4]
 			self.arg = m[4]
 			return (
 			return (
 				self.caller.conv_blkspec(m[1]),
 				self.caller.conv_blkspec(m[1]),
-				self.caller.conv_blkspec(m[3]) if m[3] else None
-			)
-		return (None,None)
+				self.caller.conv_blkspec(m[3]) if m[3] else None)
+		return (None, None)
 
 
 	def parse_add(self):
 	def parse_add(self):
-		m = re.match(r'\+([0-9*]+)(.*)',self.arg)
+		m = re.match(r'\+([0-9*]+)(.*)', self.arg)
 		if m:
 		if m:
-			res,self.arg = (m[1],m[2])
+			res, self.arg = (m[1], m[2])
 			if res.strip('*') != res:
 			if res.strip('*') != res:
-				die(1,f"'+{res}': malformed nBlocks specifier")
+				die(1, f"'+{res}': malformed nBlocks specifier")
 			if len(res) > 30:
 			if len(res) > 30:
-				die(1,f"'+{res}': overly long nBlocks specifier")
+				die(1, f"'+{res}': overly long nBlocks specifier")
 			return self.caller.check_nblocks(eval(res)) # res is only digits plus '*', so eval safe
 			return self.caller.check_nblocks(eval(res)) # res is only digits plus '*', so eval safe
 
 
 class BlocksInfo:
 class BlocksInfo:
@@ -81,33 +80,33 @@ class BlocksInfo:
 	total_solve_time = 0
 	total_solve_time = 0
 	header_printed = False
 	header_printed = False
 
 
-	bf = namedtuple('block_info_fields',['fmt_func','src','fs','hdr1','hdr2','key1','key2'])
+	bf = namedtuple('block_info_fields', ['fmt_func', 'src', 'fs', 'hdr1', 'hdr2', 'key1', 'key2'])
 	# bh=getblockheader, bs=getblockstats, lo=local
 	# bh=getblockheader, bs=getblockstats, lo=local
 	fields = {
 	fields = {
-		'block':      bf( None, 'bh', '{:<6}',  '',      'Block',     'height',              None ),
-		'hash':       bf( None, 'bh', '{:<64}', '',      'Hash',      'hash',                None ),
-		'date':       bf( 'da', 'bh', '{:<19}', '',      'Date',      'time',                None ),
-		'interval':   bf( 'td', 'lo', '{:>8}',  'Solve', 'Time ',     'interval',            None ),
-		'subsidy':    bf( 'su', 'bs', '{:<5}',  'Sub-',  'sidy',      'subsidy',             None ),
-		'totalfee':   bf( 'tf', 'bs', '{:>10}', '',      'Total Fee', 'totalfee',            None ),
-		'size':       bf( None, 'bs', '{:>7}',  '',      'Size',      'total_size',          None ),
-		'weight':     bf( None, 'bs', '{:>7}',  '',      'Weight',    'total_weight',        None ),
-		'fee90':      bf( 'fe', 'bs', '{:>3}',  '90%',   'Fee',       'feerate_percentiles', 4 ),
-		'fee75':      bf( 'fe', 'bs', '{:>3}',  '75%',   'Fee',       'feerate_percentiles', 3 ),
-		'fee50':      bf( 'fe', 'bs', '{:>3}',  '50%',   'Fee',       'feerate_percentiles', 2 ),
-		'fee25':      bf( 'fe', 'bs', '{:>3}',  '25%',   'Fee',       'feerate_percentiles', 1 ),
-		'fee10':      bf( 'fe', 'bs', '{:>3}',  '10%',   'Fee',       'feerate_percentiles', 0 ),
-		'fee_max':    bf( 'fe', 'bs', '{:>5}',  'Max',   'Fee',       'maxfeerate',          None ),
-		'fee_avg':    bf( 'fe', 'bs', '{:>3}',  'Avg',   'Fee',       'avgfeerate',          None ),
-		'fee_min':    bf( 'fe', 'bs', '{:>3}',  'Min',   'Fee',       'minfeerate',          None ),
-		'nTx':        bf( None, 'bh', '{:>5}',  '',      ' nTx ',     'nTx',                 None ),
-		'inputs':     bf( None, 'bs', '{:>5}',  'In- ',  'puts',      'ins',                 None ),
-		'outputs':    bf( None, 'bs', '{:>5}',  'Out-',  'puts',      'outs',                None ),
-		'utxo_inc':   bf( None, 'bs', '{:>6}',  ' UTXO', ' Incr',     'utxo_increase',       None ),
-		'version':    bf( None, 'bh', '{:<8}',  '',      'Version',   'versionHex',          None ),
-		'difficulty': bf( 'di', 'bh', '{:<8}',  'Diffi-','culty',     'difficulty',          None ),
-		'miner':      bf( None, 'lo', '{:<5}',  '',      'Miner',     'miner',               None ),
-	}
+		'block':      bf(None, 'bh', '{:<6}',  '',      'Block',     'height',              None),
+		'hash':       bf(None, 'bh', '{:<64}', '',      'Hash',      'hash',                None),
+		'date':       bf('da', 'bh', '{:<19}', '',      'Date',      'time',                None),
+		'interval':   bf('td', 'lo', '{:>8}',  'Solve', 'Time ',     'interval',            None),
+		'subsidy':    bf('su', 'bs', '{:<5}',  'Sub-',  'sidy',      'subsidy',             None),
+		'totalfee':   bf('tf', 'bs', '{:>10}', '',      'Total Fee', 'totalfee',            None),
+		'size':       bf(None, 'bs', '{:>7}',  '',      'Size',      'total_size',          None),
+		'weight':     bf(None, 'bs', '{:>7}',  '',      'Weight',    'total_weight',        None),
+		'fee90':      bf('fe', 'bs', '{:>3}',  '90%',   'Fee',       'feerate_percentiles', 4),
+		'fee75':      bf('fe', 'bs', '{:>3}',  '75%',   'Fee',       'feerate_percentiles', 3),
+		'fee50':      bf('fe', 'bs', '{:>3}',  '50%',   'Fee',       'feerate_percentiles', 2),
+		'fee25':      bf('fe', 'bs', '{:>3}',  '25%',   'Fee',       'feerate_percentiles', 1),
+		'fee10':      bf('fe', 'bs', '{:>3}',  '10%',   'Fee',       'feerate_percentiles', 0),
+		'fee_max':    bf('fe', 'bs', '{:>5}',  'Max',   'Fee',       'maxfeerate',          None),
+		'fee_avg':    bf('fe', 'bs', '{:>3}',  'Avg',   'Fee',       'avgfeerate',          None),
+		'fee_min':    bf('fe', 'bs', '{:>3}',  'Min',   'Fee',       'minfeerate',          None),
+		'nTx':        bf(None, 'bh', '{:>5}',  '',      ' nTx ',     'nTx',                 None),
+		'inputs':     bf(None, 'bs', '{:>5}',  'In- ',  'puts',      'ins',                 None),
+		'outputs':    bf(None, 'bs', '{:>5}',  'Out-',  'puts',      'outs',                None),
+		'utxo_inc':   bf(None, 'bs', '{:>6}',  ' UTXO', ' Incr',     'utxo_increase',       None),
+		'version':    bf(None, 'bh', '{:<8}',  '',      'Version',   'versionHex',          None),
+		'difficulty': bf('di', 'bh', '{:<8}',  'Diffi-','culty',     'difficulty',          None),
+		'miner':      bf(None, 'lo', '{:<5}',  '',      'Miner',     'miner',               None)}
+
 	dfl_fields = (
 	dfl_fields = (
 		'block',
 		'block',
 		'date',
 		'date',
@@ -121,8 +120,8 @@ class BlocksInfo:
 		'fee10',
 		'fee10',
 		'fee_avg',
 		'fee_avg',
 		'fee_min',
 		'fee_min',
-		'version',
-	)
+		'version')
+
 	fixed_fields = (
 	fixed_fields = (
 		'block',      # until ≈ 09/01/2028 (block 1000000)
 		'block',      # until ≈ 09/01/2028 (block 1000000)
 		'hash',
 		'hash',
@@ -131,36 +130,34 @@ class BlocksInfo:
 		'weight',     # until ≈ 2.5x block size increase
 		'weight',     # until ≈ 2.5x block size increase
 		'version',
 		'version',
 		'subsidy',    # until ≈ 01/04/2028 (increases by 1 digit per halving until 9th halving [max 10 digits])
 		'subsidy',    # until ≈ 01/04/2028 (increases by 1 digit per halving until 9th halving [max 10 digits])
-		'difficulty', # until 1.00e+100 (i.e. never)
-	)
+		'difficulty') # until 1.00e+100 (i.e. never)
 
 
 	# column width adjustment data:
 	# column width adjustment data:
-	fs_lsqueeze = ('totalfee','inputs','outputs','nTx')
+	fs_lsqueeze = ('totalfee', 'inputs', 'outputs', 'nTx')
 	fs_rsqueeze = ()
 	fs_rsqueeze = ()
 	fs_groups = (
 	fs_groups = (
-		('fee10','fee25','fee50','fee75','fee90','fee_avg','fee_min','fee_max'),
-	)
+		('fee10', 'fee25', 'fee50', 'fee75', 'fee90', 'fee_avg', 'fee_min', 'fee_max'))
 	fs_lsqueeze2 = ('interval',)
 	fs_lsqueeze2 = ('interval',)
 
 
-	all_stats = ['col_avg','range','avg','mini_avg','total','diff']
-	dfl_stats = ['range','mini_avg','diff']
+	all_stats = ['col_avg', 'range', 'avg', 'mini_avg', 'total', 'diff']
+	dfl_stats = ['range', 'mini_avg', 'diff']
 	noindent_stats = ['col_avg']
 	noindent_stats = ['col_avg']
 
 
-	avg_stats_skip = {'block', 'hash', 'date', 'version','miner'}
+	avg_stats_skip = {'block', 'hash', 'date', 'version', 'miner'}
 
 
-	range_data = namedtuple('parsed_range_data',['first','last','from_tip','nblocks','step'])
+	range_data = namedtuple('parsed_range_data', ['first', 'last', 'from_tip', 'nblocks', 'step'])
 
 
-	t_fmt = lambda self,t: f'{t/86400:.2f} days' if t > 172800 else f'{t/3600:.2f} hrs'
+	t_fmt = lambda self, t: f'{t/86400:.2f} days' if t > 172800 else f'{t/3600:.2f} hrs'
 
 
 	@classmethod
 	@classmethod
-	def parse_cslist(cls,uarg,full_set,dfl_set,desc):
+	def parse_cslist(cls, uarg, full_set, dfl_set, desc):
 
 
-		def make_list(m,func):
+		def make_list(m, func):
 			groups_lc = [set(e.lower() for e in gi.split(',')) for gi in m.groups()]
 			groups_lc = [set(e.lower() for e in gi.split(',')) for gi in m.groups()]
 			for group in groups_lc:
 			for group in groups_lc:
 				for e in group:
 				for e in group:
 					if e not in full_set_lc:
 					if e not in full_set_lc:
-						die(1,f'{e!r}: unrecognized {desc}')
+						die(1, f'{e!r}: unrecognized {desc}')
 			# display elements in order:
 			# display elements in order:
 			return [e for e in full_set if e.lower() in func(groups_lc)]
 			return [e for e in full_set if e.lower() in func(groups_lc)]
 
 
@@ -168,33 +165,31 @@ class BlocksInfo:
 		dfl_set_lc  = set(e.lower() for e in dfl_set)
 		dfl_set_lc  = set(e.lower() for e in dfl_set)
 		cspat = r'(\w+(?:,\w+)*)'
 		cspat = r'(\w+(?:,\w+)*)'
 
 
-		for pat,func in (
-				( rf'{cspat}$',            lambda g: g[0] ),
-				( rf'\+{cspat}$',          lambda g: dfl_set_lc | g[0] ),
-				( rf'\-{cspat}$',          lambda g: dfl_set_lc - g[0] ),
-				( rf'\+{cspat}\-{cspat}$', lambda g: ( dfl_set_lc | g[0] ) - g[1] ),
-				( rf'\-{cspat}\+{cspat}$', lambda g: ( dfl_set_lc - g[0] ) | g[1] ),
-				( rf'all\-{cspat}$',       lambda g: full_set_lc - g[0] )
-			):
-			m = re.match(pat,uarg,re.ASCII|re.IGNORECASE)
+		for pat, func in (
+				(rf'{cspat}$',            lambda g: g[0]),
+				(rf'\+{cspat}$',          lambda g: dfl_set_lc | g[0]),
+				(rf'\-{cspat}$',          lambda g: dfl_set_lc - g[0]),
+				(rf'\+{cspat}\-{cspat}$', lambda g: (dfl_set_lc | g[0]) - g[1]),
+				(rf'\-{cspat}\+{cspat}$', lambda g: (dfl_set_lc - g[0]) | g[1]),
+				(rf'all\-{cspat}$',       lambda g: full_set_lc - g[0])):
+			m = re.match(pat, uarg, re.ASCII|re.IGNORECASE)
 			if m:
 			if m:
-				return make_list(m,func)
+				return make_list(m, func)
 		else:
 		else:
-			die(1,f'{uarg}: invalid parameter')
+			die(1, f'{uarg}: invalid parameter')
 
 
-	def __init__(self,cfg,cmd_args,rpc):
+	def __init__(self, cfg, cmd_args, rpc):
 
 
-		def parse_cs_uarg(uarg,full_set,dfl_set,desc):
+		def parse_cs_uarg(uarg, full_set, dfl_set, desc):
 			return (
 			return (
 				full_set if uarg == 'all' else [] if uarg == 'none' else
 				full_set if uarg == 'all' else [] if uarg == 'none' else
-				self.parse_cslist(uarg,full_set,dfl_set,desc)
-			)
+				self.parse_cslist(uarg, full_set, dfl_set, desc))
 
 
 		def get_fields():
 		def get_fields():
-			return parse_cs_uarg(self.cfg.fields,list(self.fields),self.dfl_fields,'field')
+			return parse_cs_uarg(self.cfg.fields, list(self.fields), self.dfl_fields, 'field')
 
 
 		def get_stats():
 		def get_stats():
-			return parse_cs_uarg(self.cfg.stats.lower(),self.all_stats,self.dfl_stats,'stat')
+			return parse_cs_uarg(self.cfg.stats.lower(), self.all_stats, self.dfl_stats, 'stat')
 
 
 		def parse_cmd_args(): # => (block_list, first, last, step)
 		def parse_cmd_args(): # => (block_list, first, last, step)
 			match cmd_args:
 			match cmd_args:
@@ -217,7 +212,7 @@ class BlocksInfo:
 		from_satoshi = self.rpc.proto.coin_amt.satoshi
 		from_satoshi = self.rpc.proto.coin_amt.satoshi
 		to_satoshi = 1 / from_satoshi
 		to_satoshi = 1 / from_satoshi
 
 
-		self.block_list,self.first,self.last,self.step = parse_cmd_args()
+		self.block_list, self.first, self.last, self.step = parse_cmd_args()
 
 
 		have_segwit = self.rpc.info('segwit_is_active')
 		have_segwit = self.rpc.info('segwit_is_active')
 
 
@@ -228,35 +223,33 @@ class BlocksInfo:
 		self.stats_deps = {
 		self.stats_deps = {
 			'avg':      set(self.fields) - self.avg_stats_skip,
 			'avg':      set(self.fields) - self.avg_stats_skip,
 			'col_avg':  set(self.fields) - self.avg_stats_skip,
 			'col_avg':  set(self.fields) - self.avg_stats_skip,
-			'mini_avg': {'interval','size'} | ({'weight'} if have_segwit else set()),
-			'total':    {'interval','subsidy','totalfee','nTx','inputs','outputs','utxo_inc'},
+			'mini_avg': {'interval', 'size'} | ({'weight'} if have_segwit else set()),
+			'total':    {'interval', 'subsidy', 'totalfee', 'nTx', 'inputs', 'outputs', 'utxo_inc'},
 			'range':    {},
 			'range':    {},
-			'diff':     {},
-		}
+			'diff':     {}}
 
 
 		self.fmt_funcs = {
 		self.fmt_funcs = {
-			'da': lambda arg: strftime('%Y-%m-%d %X',gmtime(arg)),
+			'da': lambda arg: strftime('%Y-%m-%d %X', gmtime(arg)),
 			'td': lambda arg: (
 			'td': lambda arg: (
-				'-{:02}:{:02}'.format(abs(arg)//60,abs(arg)%60) if arg < 0 else
-				' {:02}:{:02}'.format(arg//60,arg%60) ),
+				'-{:02}:{:02}'.format(abs(arg)//60, abs(arg)%60) if arg < 0 else
+				' {:02}:{:02}'.format(arg//60, arg%60)),
 			'tf': lambda arg: '{:.8f}'.format(arg * from_satoshi),
 			'tf': lambda arg: '{:.8f}'.format(arg * from_satoshi),
 			'su': lambda arg: str(arg * from_satoshi).rstrip('0').rstrip('.'),
 			'su': lambda arg: str(arg * from_satoshi).rstrip('0').rstrip('.'),
 			'fe': lambda arg: str(arg),
 			'fe': lambda arg: str(arg),
-			'di': lambda arg: '{:.2e}'.format(Decimal(arg)),
-		}
+			'di': lambda arg: '{:.2e}'.format(Decimal(arg))}
 
 
 		if self.cfg.coin == 'BCH':
 		if self.cfg.coin == 'BCH':
 			self.fmt_funcs.update({
 			self.fmt_funcs.update({
 				'su': lambda arg: str(arg).rstrip('0').rstrip('.'),
 				'su': lambda arg: str(arg).rstrip('0').rstrip('.'),
 				'fe': lambda arg: str(int(Decimal(arg) * to_satoshi)),
 				'fe': lambda arg: str(int(Decimal(arg) * to_satoshi)),
-				'tf': lambda arg: '{:.8f}'.format(Decimal(arg)),
-			})
+				'tf': lambda arg: '{:.8f}'.format(Decimal(arg))})
 
 
 		self.fnames = tuple(
 		self.fnames = tuple(
-			[f for f in self.fields if self.fields[f].src == 'bh' or f == 'interval'] if self.cfg.header_info else
-			get_fields() if self.cfg.fields else
-			self.dfl_fields
-		)
+			[f for f in self.fields if self.fields[f].src == 'bh' or f == 'interval']
+				if self.cfg.header_info
+			else get_fields() if self.cfg.fields
+			else self.dfl_fields)
+
 		if self.cfg.miner_info and 'miner' not in self.fnames:
 		if self.cfg.miner_info and 'miner' not in self.fnames:
 			self.fnames += ('miner',)
 			self.fnames += ('miner',)
 
 
@@ -266,15 +259,15 @@ class BlocksInfo:
 		if 'diff' in self.stats and not self.cfg.stats and self.last != self.tip:
 		if 'diff' in self.stats and not self.cfg.stats and self.last != self.tip:
 			self.stats.remove('diff')
 			self.stats.remove('diff')
 
 
-		if {'avg','col_avg'} <= set(self.stats) and self.cfg.stats_only:
+		if {'avg', 'col_avg'} <= set(self.stats) and self.cfg.stats_only:
 			self.stats.remove('col_avg')
 			self.stats.remove('col_avg')
 
 
-		if {'avg','mini_avg'} <= set(self.stats):
+		if {'avg', 'mini_avg'} <= set(self.stats):
 			self.stats.remove('mini_avg')
 			self.stats.remove('mini_avg')
 
 
 		if self.cfg.full_stats:
 		if self.cfg.full_stats:
 			add_fnames = {fname for sname in self.stats for fname in self.stats_deps[sname]}
 			add_fnames = {fname for sname in self.stats for fname in self.stats_deps[sname]}
-			self.fnames = tuple(f for f in self.fields if f in {'block'} | set(self.fnames) | add_fnames )
+			self.fnames = tuple(f for f in self.fields if f in {'block'} | set(self.fnames) | add_fnames)
 		else:
 		else:
 			if 'col_avg' in self.stats and not self.fnames:
 			if 'col_avg' in self.stats and not self.fnames:
 				self.stats.remove('col_avg')
 				self.stats.remove('col_avg')
@@ -287,8 +280,7 @@ class BlocksInfo:
 		self.bs_keys = set(
 		self.bs_keys = set(
 			[v.key1 for v in self.fvals if v.src == 'bs'] +
 			[v.key1 for v in self.fvals if v.src == 'bs'] +
 			['total_size'] +
 			['total_size'] +
-			(['total_weight'] if have_segwit else [])
-		)
+			(['total_weight'] if have_segwit else []))
 
 
 		if 'miner' in self.fnames:
 		if 'miner' in self.fnames:
 			# capturing parens must contain only ASCII chars!
 			# capturing parens must contain only ASCII chars!
@@ -302,17 +294,16 @@ class BlocksInfo:
 				rb'([\x20-\x7e]{9,})',
 				rb'([\x20-\x7e]{9,})',
 				rb'[/^]([a-zA-Z0-9&. #/-]{5,})',
 				rb'[/^]([a-zA-Z0-9&. #/-]{5,})',
 				rb'[/^]([_a-zA-Z0-9&. #/-]+)/',
 				rb'[/^]([_a-zA-Z0-9&. #/-]+)/',
-				rb'^\x03...\W{0,5}([\\_a-zA-Z0-9&. #/-]+)[/\\]',
-			)]
+				rb'^\x03...\W{0,5}([\\_a-zA-Z0-9&. #/-]+)[/\\]')]
 
 
-		self.block_data = namedtuple('block_data',self.fnames)
-		self.deps = { v.src for v in self.fvals }
+		self.block_data = namedtuple('block_data', self.fnames)
+		self.deps = {v.src for v in self.fvals}
 
 
-	def gen_fs(self,fnames,fill=[],fill_char='-',add_name=False):
+	def gen_fs(self, fnames, fill=[], fill_char='-', add_name=False):
 		for i in range(len(fnames)):
 		for i in range(len(fnames)):
 			name = fnames[i]
 			name = fnames[i]
-			ls = (' ','')[name in self.fs_lsqueeze + self.fs_lsqueeze2]
-			rs = (' ','')[name in self.fs_rsqueeze]
+			ls = (' ', '')[name in self.fs_lsqueeze + self.fs_lsqueeze2]
+			rs = (' ', '')[name in self.fs_rsqueeze]
 			if i < len(fnames) - 1 and fnames[i+1] in self.fs_lsqueeze2:
 			if i < len(fnames) - 1 and fnames[i+1] in self.fs_lsqueeze2:
 				rs = ''
 				rs = ''
 			if i:
 			if i:
@@ -321,7 +312,7 @@ class BlocksInfo:
 						ls = ''
 						ls = ''
 						break
 						break
 			repl = (name if add_name else '') + ':' + (fill_char if name in fill else '')
 			repl = (name if add_name else '') + ':' + (fill_char if name in fill else '')
-			yield (ls + self.fields[name].fs.replace(':',repl) + rs)
+			yield (ls + self.fields[name].fs.replace(':', repl) + rs)
 
 
 	def conv_blkspec(self, arg):
 	def conv_blkspec(self, arg):
 		match arg:
 		match arg:
@@ -347,22 +338,22 @@ class BlocksInfo:
 			case _:
 			case _:
 				return arg
 				return arg
 
 
-	def parse_rangespec(self,arg):
+	def parse_rangespec(self, arg):
 
 
-		p = RangeParser(self,arg)
+		p = RangeParser(self, arg)
 
 
-		from_tip   = p.parse('from_tip')
-		first,last = (self.tip-from_tip,None) if from_tip else p.parse('abs_range')
-		add1       = p.parse('add')
-		add2       = p.parse('add')
+		from_tip    = p.parse('from_tip')
+		first, last = (self.tip-from_tip, None) if from_tip else p.parse('abs_range')
+		add1        = p.parse('add')
+		add2        = p.parse('add')
 		p.finalize()
 		p.finalize()
 
 
 		if add2 and last is not None:
 		if add2 and last is not None:
-			die(1,f'{arg!r}: invalid range specifier')
+			die(1, f'{arg!r}: invalid range specifier')
 
 
-		nblocks,step = (add1,add2) if last is None else (None,add1)
+		nblocks, step = (add1, add2) if last is None else (None, add1)
 
 
-		if p.debug: msg(repr(self.range_data(first,last,from_tip,nblocks,step)))
+		if p.debug: msg(repr(self.range_data(first, last, from_tip, nblocks, step)))
 
 
 		if nblocks:
 		if nblocks:
 			if first is None:
 			if first is None:
@@ -373,12 +364,12 @@ class BlocksInfo:
 		last  = self.conv_blkspec(last or first)
 		last  = self.conv_blkspec(last or first)
 
 
 		if p.debug:
 		if p.debug:
-			msg(repr(self.range_data(first,last,from_tip,nblocks,step)))
+			msg(repr(self.range_data(first, last, from_tip, nblocks, step)))
 
 
 		if first > last:
 		if first > last:
-			die(1,f'{first}-{last}: invalid block range')
+			die(1, f'{first}-{last}: invalid block range')
 
 
-		return self.range_data(first,last,from_tip,nblocks,step)
+		return self.range_data(first, last, from_tip, nblocks, step)
 
 
 	async def process_blocks(self):
 	async def process_blocks(self):
 
 
@@ -388,7 +379,7 @@ class BlocksInfo:
 
 
 		c = self.rpc
 		c = self.rpc
 
 
-		heights = self.block_list or range(self.first,self.last+1)
+		heights = self.block_list or range(self.first, self.last+1)
 		self.hdrs = await get_hdrs(heights)
 		self.hdrs = await get_hdrs(heights)
 
 
 		if self.block_list:
 		if self.block_list:
@@ -397,8 +388,7 @@ class BlocksInfo:
 		else:
 		else:
 			self.first_prev_hdr = (
 			self.first_prev_hdr = (
 				self.hdrs[0] if heights[0] == 0 else
 				self.hdrs[0] if heights[0] == 0 else
-				await c.call('getblockheader',await c.call('getblockhash',heights[0]-1))
-			)
+				await c.call('getblockheader', await c.call('getblockhash', heights[0]-1)))
 
 
 		self.t_cur = self.first_prev_hdr['time']
 		self.t_cur = self.first_prev_hdr['time']
 		self.res = []
 		self.res = []
@@ -409,16 +399,16 @@ class BlocksInfo:
 			ret = await self.process_block(self.hdrs[n])
 			ret = await self.process_block(self.hdrs[n])
 			self.res.append(ret)
 			self.res.append(ret)
 			if self.fnames and not self.cfg.stats_only:
 			if self.fnames and not self.cfg.stats_only:
-				self.output_block(ret,n)
+				self.output_block(ret, n)
 
 
-	def output_block(self,data,n):
+	def output_block(self, data, n):
 		def gen():
 		def gen():
-			for k,v in data._asdict().items():
+			for k, v in data._asdict().items():
 				func = self.fields[k].fmt_func
 				func = self.fields[k].fmt_func
 				yield self.fmt_funcs[func](v) if func else v
 				yield self.fmt_funcs[func](v) if func else v
 		Msg(self.fs.format(*gen()))
 		Msg(self.fs.format(*gen()))
 
 
-	async def process_block(self,hdr):
+	async def process_block(self, hdr):
 
 
 		self.t_diff = hdr['time'] - self.t_cur
 		self.t_diff = hdr['time'] - self.t_cur
 		self.t_cur  = hdr['time']
 		self.t_cur  = hdr['time']
@@ -426,14 +416,12 @@ class BlocksInfo:
 
 
 		blk_data = {
 		blk_data = {
 			'bh': hdr,
 			'bh': hdr,
-			'lo': { 'interval': self.t_diff }
-		}
+			'lo': {'interval': self.t_diff}}
 
 
 		if 'bs' in self.deps:
 		if 'bs' in self.deps:
 			bs = (
 			bs = (
 				self.genesis_stats if hdr['height'] == 0 else
 				self.genesis_stats if hdr['height'] == 0 else
-				await self.rpc.call('getblockstats',hdr['hash'],list(self.bs_keys))
-			)
+				await self.rpc.call('getblockstats', hdr['hash'], list(self.bs_keys)))
 			self.total_bytes += bs['total_size']
 			self.total_bytes += bs['total_size']
 			if 'total_weight' in bs:
 			if 'total_weight' in bs:
 				self.total_weight += bs['total_weight']
 				self.total_weight += bs['total_weight']
@@ -446,14 +434,13 @@ class BlocksInfo:
 			for v in self.fvals:
 			for v in self.fvals:
 				yield (
 				yield (
 					blk_data[v.src][v.key1] if v.key2 is None else
 					blk_data[v.src][v.key1] if v.key2 is None else
-					blk_data[v.src][v.key1][v.key2]
-				)
+					blk_data[v.src][v.key1][v.key2])
 
 
 		return self.block_data(*gen())
 		return self.block_data(*gen())
 
 
-	async def get_miner_string(self,H):
-		tx0 = (await self.rpc.call('getblock',H))['tx'][0]
-		bd = await self.rpc.call('getrawtransaction',tx0,1)
+	async def get_miner_string(self, H):
+		tx0 = (await self.rpc.call('getblock', H))['tx'][0]
+		bd = await self.rpc.call('getrawtransaction', tx0, 1)
 		if type(bd) == tuple:
 		if type(bd) == tuple:
 			return '---'
 			return '---'
 		else:
 		else:
@@ -464,13 +451,12 @@ class BlocksInfo:
 				trmap_in = {
 				trmap_in = {
 					'\\': ' ',
 					'\\': ' ',
 					'/': ' ',
 					'/': ' ',
-					',': ' ',
-				}
-				trmap = { ord(a):b for a,b in trmap_in.items() }
+					',': ' '}
+				trmap = {ord(a): b for a, b in trmap_in.items()}
 				for pat in self.miner_pats:
 				for pat in self.miner_pats:
 					m = pat.search(cb)
 					m = pat.search(cb)
 					if m:
 					if m:
-						return re.sub( r'\s+', ' ', m[1].decode().strip('^').translate(trmap).strip() )
+						return re.sub(r'\s+', ' ', m[1].decode().strip('^').translate(trmap).strip())
 			return ''
 			return ''
 
 
 	def print_header(self):
 	def print_header(self):
@@ -484,11 +470,11 @@ class BlocksInfo:
 			yield self.fs.format(*hdr1)
 			yield self.fs.format(*hdr1)
 		yield self.fs.format(*hdr2)
 		yield self.fs.format(*hdr2)
 
 
-	def process_stats(self,sname):
-		method = getattr(self,f'create_{sname}_stats',None)
-		return self.output_stats(method() if method else self.create_stats(sname),sname)
+	def process_stats(self, 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):
+	def fmt_stat_item(self, fs, s):
 		return fs.format(s) if type(fs) == str else fs(s)
 		return fs.format(s) if type(fs) == str else fs(s)
 
 
 	async def output_stats(self, res, sname):
 	async def output_stats(self, res, sname):
@@ -497,7 +483,7 @@ class BlocksInfo:
 			for d in data:
 			for d in data:
 				match d:
 				match d:
 					case [a, b]:
 					case [a, b]:
-						yield (indent + a).format(**{k:self.fmt_stat_item(*v) for k, v in b.items()})
+						yield (indent + a).format(**{k: self.fmt_stat_item(*v) for k, v in b.items()})
 					case [a, _, b, c]:
 					case [a, _, b, c]:
 						yield (indent + a).format(self.fmt_stat_item(b, c))
 						yield (indent + a).format(self.fmt_stat_item(b, c))
 					case str():
 					case str():
@@ -524,15 +510,14 @@ class BlocksInfo:
 					'range':   ('{}', self.hdrs[-1]['height'] - self.hdrs[0]['height'] + 1),
 					'range':   ('{}', self.hdrs[-1]['height'] - self.hdrs[0]['height'] + 1),
 					'elapsed': (self.t_fmt, elapsed),
 					'elapsed': (self.t_fmt, elapsed),
 					'nBlocks': ('{}', total_blks),
 					'nBlocks': ('{}', total_blks),
-					'step':    ('{}', self.step),
-				}
-			)
+					'step':    ('{}', self.step)})
+
 			if elapsed:
 			if elapsed:
-				yield ( 'Start:      {}',       'start_date',  self.fmt_funcs['da'], self.hdrs[0]['time']  )
-				yield ( 'End:        {}',       'end_date',    self.fmt_funcs['da'], self.hdrs[-1]['time']  )
-				yield ( 'Avg BDI:    {} min',   'avg_bdi',     '{:.2f}',  elapsed / nblocks / 60 )
+				yield ('Start:      {}',       'start_date',  self.fmt_funcs['da'], self.hdrs[0]['time'])
+				yield ('End:        {}',       'end_date',    self.fmt_funcs['da'], self.hdrs[-1]['time'])
+				yield ('Avg BDI:    {} min',   'avg_bdi',     '{:.2f}',  elapsed / nblocks / 60)
 
 
-		return ( 'range', gen() )
+		return ('range', gen())
 
 
 	async def create_diff_stats(self):
 	async def create_diff_stats(self):
 
 
@@ -541,18 +526,17 @@ class BlocksInfo:
 
 
 		tip_hdr = (
 		tip_hdr = (
 			self.hdrs[-1] if self.hdrs[-1]['height'] == self.tip else
 			self.hdrs[-1] if self.hdrs[-1]['height'] == self.tip else
-			await c.call('getblockheader',await c.call('getblockhash',self.tip))
-		)
+			await c.call('getblockheader', await c.call('getblockhash', self.tip)))
 
 
 		min_sample_blks = 432 # ≈3 days
 		min_sample_blks = 432 # ≈3 days
-		rel_hdr = await c.call('getblockheader',await c.call('getblockhash',self.tip-rel))
+		rel_hdr = await c.call('getblockheader', await c.call('getblockhash', self.tip-rel))
 
 
 		if rel >= min_sample_blks:
 		if rel >= min_sample_blks:
 			sample_blks = rel
 			sample_blks = rel
-			bdi = ( tip_hdr['time'] - rel_hdr['time'] ) / rel
+			bdi = (tip_hdr['time'] - rel_hdr['time']) / rel
 		else:
 		else:
-			sample_blks = min(min_sample_blks,self.tip)
-			start_hdr = await c.call('getblockheader',await c.call('getblockhash',self.tip-sample_blks))
+			sample_blks = min(min_sample_blks, self.tip)
+			start_hdr = await c.call('getblockheader', await c.call('getblockhash', self.tip-sample_blks))
 			diff_adj = Decimal(tip_hdr['difficulty']) / Decimal(start_hdr['difficulty'])
 			diff_adj = Decimal(tip_hdr['difficulty']) / Decimal(start_hdr['difficulty'])
 			time1 = rel_hdr['time'] - start_hdr['time']
 			time1 = rel_hdr['time'] - start_hdr['time']
 			time2 = tip_hdr['time'] - rel_hdr['time']
 			time2 = tip_hdr['time'] - rel_hdr['time']
@@ -560,7 +544,7 @@ class BlocksInfo:
 
 
 		rem = self.rpc.proto.diff_adjust_interval - rel
 		rem = self.rpc.proto.diff_adjust_interval - rel
 
 
-		return ( 'difficulty', (
+		return ('difficulty', (
 			'Difficulty Statistics:',
 			'Difficulty Statistics:',
 			('Current height:    {}', 'chain_tip', '{}', self.tip),
 			('Current height:    {}', 'chain_tip', '{}', self.tip),
 			('Next diff adjust:  {next_diff_adjust} (in {blks_remaining} block%s [{time_remaining}])' % suf(rem),
 			('Next diff adjust:  {next_diff_adjust} (in {blks_remaining} block%s [{time_remaining}])' % suf(rem),
@@ -593,105 +577,98 @@ class BlocksInfo:
 		def gen():
 		def gen():
 			for field in self.fnames:
 			for field in self.fnames:
 				if field in self.avg_stats_skip:
 				if field in self.avg_stats_skip:
-					yield ( field, ('{}','') )
+					yield (field, ('{}', ''))
 				else:
 				else:
 					ret = self.sum_field_avg(field)
 					ret = self.sum_field_avg(field)
 					func = self.fields[field].fmt_func
 					func = self.fields[field].fmt_func
-					yield ( field, ( (self.fmt_funcs[func] if func else '{}'), ret ))
+					yield (field, ((self.fmt_funcs[func] if func else '{}'), ret))
 		if not self.header_printed:
 		if not self.header_printed:
 			self.print_header()
 			self.print_header()
-		fs = ''.join(self.gen_fs(self.fnames,fill=self.avg_stats_skip,add_name=True)).strip()
-		return ('column_averages', ('Column averages:', (fs, dict(gen())) ))
+		fs = ''.join(self.gen_fs(self.fnames, fill=self.avg_stats_skip, add_name=True)).strip()
+		return ('column_averages', ('Column averages:', (fs, dict(gen()))))
 
 
-	def avg_stats_data(self,data,spec_conv,spec_val):
+	def avg_stats_data(self, data, spec_conv, spec_val):
 		coin = self.rpc.proto.coin
 		coin = self.rpc.proto.coin
 
 
 		return data(
 		return data(
 			hdr = 'Averages for processed blocks:',
 			hdr = 'Averages for processed blocks:',
 			func = self.sum_field_avg,
 			func = self.sum_field_avg,
-			spec_sufs = { 'subsidy': f' {coin}', 'totalfee': f' {coin}' },
+			spec_sufs = {'subsidy': f' {coin}', 'totalfee': f' {coin}'},
 			spec_convs = {
 			spec_convs = {
-				'interval':    spec_conv(0,  lambda arg: secs_to_ms(arg)),
+				'interval':    spec_conv(0, lambda arg: secs_to_ms(arg)),
 				'utxo_inc':    spec_conv(-1, '{:<+}'),
 				'utxo_inc':    spec_conv(-1, '{:<+}'),
-				'mb_per_hour': spec_conv(0,  '{}'),
-			},
+				'mb_per_hour': spec_conv(0, '{}')},
 			spec_vals = (
 			spec_vals = (
 				spec_val(
 				spec_val(
 					'mb_per_hour', 'MB/hr', 'interval',
 					'mb_per_hour', 'MB/hr', 'interval',
 					lambda values: 'bs' in self.deps,
 					lambda values: 'bs' in self.deps,
 					lambda values: (
 					lambda values: (
 						'{:.4f}'.format((self.total_bytes / 10000) / (self.total_solve_time / 36))
 						'{:.4f}'.format((self.total_bytes / 10000) / (self.total_solve_time / 36))
-						if self.total_solve_time else 'N/A' ),
-				),
-			)
-		)
+						if self.total_solve_time else 'N/A')),
+				))
 
 
 	mini_avg_stats_data = avg_stats_data
 	mini_avg_stats_data = avg_stats_data
 
 
-	def total_stats_data(self,data,spec_conv,spec_val):
+	def total_stats_data(self, data, spec_conv, spec_val):
 		coin = self.rpc.proto.coin
 		coin = self.rpc.proto.coin
 		return data(
 		return data(
 			hdr = 'Totals for processed blocks:',
 			hdr = 'Totals for processed blocks:',
 			func = self.sum_field_total,
 			func = self.sum_field_total,
-			spec_sufs = { 'subsidy': f' {coin}', 'totalfee': f' {coin}', 'reward': f' {coin}' },
+			spec_sufs = {'subsidy': f' {coin}', 'totalfee': f' {coin}', 'reward': f' {coin}'},
 			spec_convs = {
 			spec_convs = {
-				'interval': spec_conv(0,  lambda arg: secs_to_dhms(arg)),
+				'interval': spec_conv(0, lambda arg: secs_to_dhms(arg)),
 				'utxo_inc': spec_conv(-1, '{:<+}'),
 				'utxo_inc': spec_conv(-1, '{:<+}'),
-				'reward':   spec_conv(0,  self.fmt_funcs['tf']),
-			},
+				'reward':   spec_conv(0, self.fmt_funcs['tf'])},
 			spec_vals = (
 			spec_vals = (
 				spec_val(
 				spec_val(
 					'reward', 'Reward', 'totalfee',
 					'reward', 'Reward', 'totalfee',
-					lambda values: {'subsidy','totalfee'} <= set(values),
-					lambda values: values['subsidy'] + values['totalfee']
-				),
-			)
-		)
+					lambda values: {'subsidy', 'totalfee'} <= set(values),
+					lambda values: values['subsidy'] + values['totalfee']),
+				))
 
 
-	async def create_stats(self,sname):
+	async def create_stats(self, sname):
 
 
 		def convert_stats_hdr(field):
 		def convert_stats_hdr(field):
 			v = self.fields[field]
 			v = self.fields[field]
-			return '{} {}'.format(v.hdr1.strip(), v.hdr2.strip()).replace('- ','') if v.hdr1 else v.hdr2.strip()
+			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'])
-		)
+		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]]
 		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
+		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
 
 
+		print(d.spec_vals)
 		for v in d.spec_vals:
 		for v in d.spec_vals:
+			print(v)
 			if v.condition(values):
 			if v.condition(values):
 				try:    idx = fnames.index(v.insert_after) + 1
 				try:    idx = fnames.index(v.insert_after) + 1
 				except: idx = 0
 				except: idx = 0
-				fnames.insert(idx,v.name)
+				fnames.insert(idx, v.name)
 				lbls[v.name] = v.lbl
 				lbls[v.name] = v.lbl
 				values[v.name] = v.code(values)
 				values[v.name] = v.code(values)
 
 
 		def gen():
 		def gen():
-			for n,fname in enumerate(fnames):
+			for n, fname in enumerate(fnames):
 				spec_conv = d.spec_convs.get(fname)
 				spec_conv = d.spec_convs.get(fname)
 				yield (
 				yield (
 					'{lbl:{wid}} {{}}{suf}'.format(
 					'{lbl:{wid}} {{}}{suf}'.format(
 						lbl = lbls[fname] + ':',
 						lbl = lbls[fname] + ':',
 						wid = col1_w + (spec_conv.width_adj if spec_conv else 0),
 						wid = col1_w + (spec_conv.width_adj if spec_conv else 0),
-						suf = d.spec_sufs.get(fname) or ''
-					),
+						suf = d.spec_sufs.get(fname) or ''),
 					fname,
 					fname,
 					spec_conv.conv if spec_conv else (
 					spec_conv.conv if spec_conv else (
-						(lambda x: self.fmt_funcs[x] if x else '{}')(self.fields[fname].fmt_func)
-					),
-					values[fname]
-				)
+						(lambda x: self.fmt_funcs[x] if x else '{}')(self.fields[fname].fmt_func)),
+					values[fname])
 
 
-		return ( sname, (d.hdr,) + tuple(gen()) )
+		return (sname, (d.hdr,) + tuple(gen()))
 
 
-	def process_stats_pre(self,i):
+	def process_stats_pre(self, i):
 		if (self.fnames and not self.cfg.stats_only) or i != 0:
 		if (self.fnames and not self.cfg.stats_only) or i != 0:
 			Msg('')
 			Msg('')
 
 
@@ -724,13 +701,12 @@ class BlocksInfo:
 		'totalfee': 0,
 		'totalfee': 0,
 		'txs': 1,
 		'txs': 1,
 		'utxo_increase': 1,
 		'utxo_increase': 1,
-		'utxo_size_inc': 117
-	}
+		'utxo_size_inc': 117}
 
 
 class JSONBlocksInfo(BlocksInfo):
 class JSONBlocksInfo(BlocksInfo):
 
 
-	def __init__(self,cfg,cmd_args,rpc):
-		super().__init__(cfg,cmd_args,rpc)
+	def __init__(self, cfg, cmd_args, rpc):
+		super().__init__(cfg, cmd_args, rpc)
 		if self.cfg.json_raw:
 		if self.cfg.json_raw:
 			self.output_block = self.output_block_raw
 			self.output_block = self.output_block_raw
 			self.fmt_stat_item = self.fmt_stat_item_raw
 			self.fmt_stat_item = self.fmt_stat_item_raw
@@ -741,22 +717,22 @@ class JSONBlocksInfo(BlocksInfo):
 		await super().process_blocks()
 		await super().process_blocks()
 		Msg_r(']')
 		Msg_r(']')
 
 
-	def output_block_raw(self,data,n):
-		Msg_r( (', ','')[n==0] + json.dumps(data._asdict(),cls=json_encoder) )
+	def output_block_raw(self, data, n):
+		Msg_r((',  ', '')[n==0] + json.dumps(data._asdict(), cls=json_encoder))
 
 
-	def output_block(self,data,n):
+	def output_block(self, data, n):
 		def gen():
 		def gen():
-			for k,v in data._asdict().items():
+			for k, v in data._asdict().items():
 				func = self.fields[k].fmt_func
 				func = self.fields[k].fmt_func
-				yield ( k, (self.fmt_funcs[func](v) if func else v) )
-		Msg_r( (', ','')[n==0] + json.dumps(dict(gen()),cls=json_encoder) )
+				yield (k, (self.fmt_funcs[func](v) if func else v))
+		Msg_r((', ', '')[n==0] + json.dumps(dict(gen()), cls=json_encoder))
 
 
 	def print_header(self): pass
 	def print_header(self): pass
 
 
-	def fmt_stat_item_raw(self,fs,s):
+	def fmt_stat_item_raw(self, fs, s):
 		return s
 		return s
 
 
-	async def output_stats(self,res,sname):
+	async def output_stats(self, res, sname):
 
 
 		def gen(data):
 		def gen(data):
 			for d in data:
 			for d in data:
@@ -771,10 +747,10 @@ class JSONBlocksInfo(BlocksInfo):
 					case _:
 					case _:
 						assert False, f'{d}: invalid stats data'
 						assert False, f'{d}: invalid stats data'
 
 
-		varname,data = await res
-		Msg_r(', "{}_data": {}'.format( varname, json.dumps(dict(gen(data)),cls=json_encoder) ))
+		varname, data = await res
+		Msg_r(', "{}_data": {}'.format(varname, json.dumps(dict(gen(data)), cls=json_encoder)))
 
 
-	def process_stats_pre(self,i): pass
+	def process_stats_pre(self, i): pass
 
 
 	def finalize_output(self):
 	def finalize_output(self):
 		Msg('}')
 		Msg('}')

+ 27 - 28
mmgen_node_tools/PeerBlocks.py

@@ -14,66 +14,66 @@ mmgen_node_tools.PeerBlocks: List blocks in flight, disconnect stalling nodes
 
 
 import asyncio
 import asyncio
 from collections import namedtuple
 from collections import namedtuple
-from mmgen.util import msg,msg_r,is_int
-from mmgen.term import get_term,get_terminal_size,get_char
+from mmgen.util import msg, msg_r, is_int
+from mmgen.term import get_term, get_terminal_size, get_char
 from mmgen.ui import line_input
 from mmgen.ui import line_input
 from .PollDisplay import PollDisplay
 from .PollDisplay import PollDisplay
 
 
-RED,RESET = ('\033[31m','\033[0m')
-COLORS = ['\033[38;5;%s;1m' % c for c in list(range(247,256)) + [231]]
-ERASE_ALL,CUR_HOME = ('\033[J','\033[H')
-CUR_HIDE,CUR_SHOW = ('\033[?25l','\033[?25h')
+RED, RESET = ('\033[31m', '\033[0m')
+COLORS = ['\033[38;5;%s;1m' % c for c in list(range(247, 256)) + [231]]
+ERASE_ALL, CUR_HOME = ('\033[J', '\033[H')
+CUR_HIDE, CUR_SHOW = ('\033[?25l', '\033[?25h')
 term = None
 term = None
 
 
 class Display(PollDisplay):
 class Display(PollDisplay):
 
 
 	poll_secs = 2
 	poll_secs = 2
 
 
-	def __init__(self,cfg):
+	def __init__(self, cfg):
 
 
 		super().__init__(cfg)
 		super().__init__(cfg)
 
 
-		global term,term_width
+		global term, term_width
 		if not term:
 		if not term:
 			term = get_term()
 			term = get_term()
 			term.init(noecho=True)
 			term.init(noecho=True)
 			term_width = self.cfg.columns or get_terminal_size().width
 			term_width = self.cfg.columns or get_terminal_size().width
 			msg_r(CUR_HOME+ERASE_ALL+CUR_HOME)
 			msg_r(CUR_HOME+ERASE_ALL+CUR_HOME)
 
 
-	async def get_info(self,rpc):
+	async def get_info(self, rpc):
 		return await rpc.call('getpeerinfo')
 		return await rpc.call('getpeerinfo')
 
 
-	def display(self,count):
+	def display(self, count):
 		msg_r(
 		msg_r(
 			CUR_HOME
 			CUR_HOME
 			+ (ERASE_ALL if count == 1 else '')
 			+ (ERASE_ALL if count == 1 else '')
 			+ 'CONNECTED PEERS ({a}) {b} - poll {c}'.format(
 			+ 'CONNECTED PEERS ({a}) {b} - poll {c}'.format(
 				a = len(self.info),
 				a = len(self.info),
 				b = self.desc,
 				b = self.desc,
-				c = count ).ljust(term_width)[:term_width]
+				c = count).ljust(term_width)[:term_width]
 			+ '\n'
 			+ '\n'
 			+ ('\n'.join(self.gen_display()) + '\n' if self.info else '')
 			+ ('\n'.join(self.gen_display()) + '\n' if self.info else '')
 			+ ERASE_ALL
 			+ ERASE_ALL
 			+ f"Type a peer number to disconnect, 'q' to quit, or any other key for {self.other_desc} display:"
 			+ f"Type a peer number to disconnect, 'q' to quit, or any other key for {self.other_desc} display:"
-			+ '\b' )
+			+ '\b')
 
 
-	async def disconnect_node(self,rpc,addr):
-		return await rpc.call('disconnectnode',addr)
+	async def disconnect_node(self, rpc, addr):
+		return await rpc.call('disconnectnode', addr)
 
 
 	def get_input(self):
 	def get_input(self):
-		s = get_char(immed_chars='q0123456789',prehold_protect=False,num_bytes=1)
+		s = get_char(immed_chars='q0123456789', prehold_protect=False, num_bytes=1)
 		if not is_int(s):
 		if not is_int(s):
 			return s
 			return s
 		with self.info_lock:
 		with self.info_lock:
 			msg('')
 			msg('')
 			term.reset()
 			term.reset()
 			# readline required for correct operation here; without it, user must re-type first digit
 			# readline required for correct operation here; without it, user must re-type first digit
-			ret = line_input( self.cfg, 'peer number> ', insert_txt=s, hold_protect=False )
+			ret = line_input(self.cfg, 'peer number> ', insert_txt=s, hold_protect=False)
 			term.init(noecho=True)
 			term.init(noecho=True)
 			self.enable_display = False # prevent display from updating before process_input()
 			self.enable_display = False # prevent display from updating before process_input()
 			return ret
 			return ret
 
 
-	async def process_input(self,rpc):
+	async def process_input(self, rpc):
 
 
 		ids = tuple(str(i['id']) for i in self.info)
 		ids = tuple(str(i['id']) for i in self.info)
 		ret = False
 		ret = False
@@ -83,7 +83,7 @@ class Display(PollDisplay):
 			from mmgen.exception import RPCFailure
 			from mmgen.exception import RPCFailure
 			addr = self.info[ids.index(self.input)]['addr']
 			addr = self.info[ids.index(self.input)]['addr']
 			try:
 			try:
-				await self.disconnect_node(rpc,addr)
+				await self.disconnect_node(rpc, addr)
 			except RPCFailure:
 			except RPCFailure:
 				msg_r(f'Unable to disconnect peer {self.input} ({addr})')
 				msg_r(f'Unable to disconnect peer {self.input} ({addr})')
 			else:
 			else:
@@ -105,8 +105,8 @@ class BlocksDisplay(Display):
 
 
 	def gen_display(self):
 	def gen_display(self):
 
 
-		pd = namedtuple('peer_data',['id','blks_data','blks_width'])
-		bd = namedtuple('block_datum',['num','disp'])
+		pd = namedtuple('peer_data', ['id', 'blks_data', 'blks_width'])
+		bd = namedtuple('block_datum', ['num', 'disp'])
 
 
 		def gen_block_data():
 		def gen_block_data():
 			global min_height
 			global min_height
@@ -114,15 +114,15 @@ class BlocksDisplay(Display):
 			for d in self.info:
 			for d in self.info:
 				if d.get('inflight'):
 				if d.get('inflight'):
 					blocks = d['inflight']
 					blocks = d['inflight']
-					min_height = min(blocks) if not min_height else min(min_height,min(blocks))
-					line = ' '.join(map(str,blocks))[:blks_field_width]
+					min_height = min(blocks) if not min_height else min(min_height, min(blocks))
+					line = ' '.join(map(str, blocks))[:blks_field_width]
 					blocks_disp = line.split()
 					blocks_disp = line.split()
 					yield pd(
 					yield pd(
 						d['id'],
 						d['id'],
-						[bd(blocks[i],blocks_disp[i]) for i in range(len(blocks_disp))],
-						len(line) )
+						[bd(blocks[i], blocks_disp[i]) for i in range(len(blocks_disp))],
+						len(line))
 				else:
 				else:
-					yield pd(d['id'],[],0)
+					yield pd(d['id'], [], 0)
 
 
 		def gen_line(peer_data):
 		def gen_line(peer_data):
 			for blk in peer_data.blks_data:
 			for blk in peer_data.blks_data:
@@ -136,7 +136,7 @@ class BlocksDisplay(Display):
 		for peer_data in tuple(gen_block_data()):
 		for peer_data in tuple(gen_block_data()):
 			yield fs.format(
 			yield fs.format(
 				peer_data.id,
 				peer_data.id,
-				' '.join(gen_line(peer_data)) + ' ' * (blks_field_width - peer_data.blks_width) )
+				' '.join(gen_line(peer_data)) + ' ' * (blks_field_width - peer_data.blks_width))
 
 
 class PeersDisplay(Display):
 class PeersDisplay(Display):
 
 
@@ -152,5 +152,4 @@ class PeersDisplay(Display):
 				A = id_width,
 				A = id_width,
 				b = d['addr'],
 				b = d['addr'],
 				B = addr_width,
 				B = addr_width,
-				c = d['subver']
-			).ljust(term_width)[:term_width]
+				c = d['subver']).ljust(term_width)[:term_width]

+ 6 - 6
mmgen_node_tools/PollDisplay.py

@@ -12,7 +12,7 @@
 mmgen_node_tools.PollDisplay: update and display RPC data; get input from user
 mmgen_node_tools.PollDisplay: update and display RPC data; get input from user
 """
 """
 
 
-import sys,threading
+import sys, threading
 from mmgen.util import msg
 from mmgen.util import msg
 from mmgen.term import get_char
 from mmgen.term import get_char
 
 
@@ -22,18 +22,18 @@ class PollDisplay:
 	input = None
 	input = None
 	poll_secs = 1
 	poll_secs = 1
 
 
-	def __init__(self,cfg):
+	def __init__(self, cfg):
 		self.cfg = cfg
 		self.cfg = cfg
 		self.info_lock = threading.Lock() # self.info accessed by 2 threads
 		self.info_lock = threading.Lock() # self.info accessed by 2 threads
 		self.display_kill_flag = threading.Event()
 		self.display_kill_flag = threading.Event()
 
 
 	def get_input(self):
 	def get_input(self):
-		return get_char(immed_chars='q',prehold_protect=False,num_bytes=1)
+		return get_char(immed_chars='q', prehold_protect=False, num_bytes=1)
 
 
-	async def process_input(self,rpc):
+	async def process_input(self, rpc):
 		return True
 		return True
 
 
-	async def run(self,rpc):
+	async def run(self, rpc):
 
 
 		async def do_display():
 		async def do_display():
 			with self.info_lock:
 			with self.info_lock:
@@ -68,7 +68,7 @@ class PollDisplay:
 			self.display_kill_flag.set()
 			self.display_kill_flag.set()
 
 
 		while True:
 		while True:
-			threading.Thread(target=get_input,daemon=True).start()
+			threading.Thread(target=get_input, daemon=True).start()
 			await do_display()
 			await do_display()
 			if await process_input():
 			if await process_input():
 				break
 				break

+ 16 - 16
mmgen_node_tools/Sound.py

@@ -19,28 +19,28 @@
 mmgen_node_tools.Sound: audio-related functions for MMGen node tools
 mmgen_node_tools.Sound: audio-related functions for MMGen node tools
 """
 """
 
 
-import sys,os,time
+import sys, os, time
 
 
 from mmgen.util import die
 from mmgen.util import die
 
 
 from mmgen_node_tools.Util import do_system
 from mmgen_node_tools.Util import do_system
 
 
 _alsa_config_file = '/tmp/alsa-config-' + os.path.basename(sys.argv[0])
 _alsa_config_file = '/tmp/alsa-config-' + os.path.basename(sys.argv[0])
-_dvols = { 'Master': 78, 'Speaker': 78, 'Headphone': 15, 'PCM': 190 }
+_dvols = {'Master': 78, 'Speaker': 78, 'Headphone': 15, 'PCM': 190}
 
 
 def timespec2secs(ts):
 def timespec2secs(ts):
 	import re
 	import re
-	mul = { 's': 1, 'm': 60, 'h': 60*60, 'd': 60*60*24 }
+	mul = {'s': 1, 'm': 60, 'h': 60*60, 'd': 60*60*24}
 	pat = r'^([0-9]+)([smhd]*)$'
 	pat = r'^([0-9]+)([smhd]*)$'
-	m = re.match(pat,ts)
+	m = re.match(pat, ts)
 	if m is None:
 	if m is None:
 		die(2,"'%s': invalid time specifier" % ts)
 		die(2,"'%s': invalid time specifier" % ts)
-	a,b = m.groups()
+	a, b = m.groups()
 	return int(a) * (mul[b] if b else 1)
 	return int(a) * (mul[b] if b else 1)
 
 
 def parse_repeat_spec(rs):
 def parse_repeat_spec(rs):
-	return [(timespec2secs(i),timespec2secs(j))
-				for i,j in [a.split(':') for a in rs.split(',')]]
+	return [(timespec2secs(i), timespec2secs(j))
+		for i, j in [a.split(':') for a in rs.split(',')]]
 
 
 def init_sound():
 def init_sound():
 	def _restore_sound():
 	def _restore_sound():
@@ -51,33 +51,33 @@ def init_sound():
 	atexit.register(_restore_sound)
 	atexit.register(_restore_sound)
 	do_system('sudo alsactl store -f ' + _alsa_config_file)
 	do_system('sudo alsactl store -f ' + _alsa_config_file)
 
 
-def play_sound(fn,vol,repeat_spec='',remote_host='',kill_flg=None,testing=False):
+def play_sound(fn, vol, repeat_spec='', remote_host='', kill_flg=None, testing=False):
 	if not remote_host:
 	if not remote_host:
 		do_system('sudo alsactl store -f ' + _alsa_config_file)
 		do_system('sudo alsactl store -f ' + _alsa_config_file)
-		for k in 'Master','Speaker','Headphone':
-			do_system(('sudo amixer -q set %s on' % k),testing)
+		for k in 'Master', 'Speaker', 'Headphone':
+			do_system(('sudo amixer -q set %s on' % k), testing)
 #		do_system('amixer -q set Headphone off')
 #		do_system('amixer -q set Headphone off')
 
 
-		vols = dict([(k,int(_dvols[k] * float(vol) / 100)) for k in _dvols])
+		vols = dict([(k, int(_dvols[k] * float(vol) / 100)) for k in _dvols])
 		for k in vols:
 		for k in vols:
-			do_system('sudo amixer -q set %s %s' % (k,vols[k]),testing)
+			do_system('sudo amixer -q set %s %s' % (k, vols[k]), testing)
 
 
 	fn = os.path.expanduser(fn)
 	fn = os.path.expanduser(fn)
 	cmd = (
 	cmd = (
 		'aplay -q %s' % fn,
 		'aplay -q %s' % fn,
-		'ssh %s mmnode-play-sound -v%d %s' % (remote_host,vol,fn)
+		'ssh %s mmnode-play-sound -v%d %s' % (remote_host, vol, fn)
 	)[bool(remote_host)]
 	)[bool(remote_host)]
 
 
 	if repeat_spec and kill_flg:
 	if repeat_spec and kill_flg:
-		for interval,duration in parse_repeat_spec(repeat_spec):
+		for interval, duration in parse_repeat_spec(repeat_spec):
 			start = time.time()
 			start = time.time()
 			while time.time() < start + duration:
 			while time.time() < start + duration:
-				do_system(cmd,testing)
+				do_system(cmd, testing)
 				if kill_flg.wait(interval):
 				if kill_flg.wait(interval):
 					if not remote_host:
 					if not remote_host:
 						do_system('sudo alsactl restore -f ' + _alsa_config_file)
 						do_system('sudo alsactl restore -f ' + _alsa_config_file)
 					return
 					return
 	else: # Play once
 	else: # Play once
-		do_system(cmd,testing)
+		do_system(cmd, testing)
 		if not remote_host:
 		if not remote_host:
 			do_system('sudo alsactl restore -f ' + _alsa_config_file)
 			do_system('sudo alsactl restore -f ' + _alsa_config_file)

File diff suppressed because it is too large
+ 205 - 231
mmgen_node_tools/Ticker.py


+ 29 - 31
mmgen_node_tools/Util.py

@@ -21,53 +21,52 @@ mmgen_node_tools.Util: utility functions for MMGen node tools
 
 
 import time
 import time
 
 
-def get_hms(t=None,utc=False,no_secs=False):
+def get_hms(t=None, utc=False, no_secs=False):
 	secs = t or time.time()
 	secs = t or time.time()
-	ret = (time.localtime,time.gmtime)[utc](secs)
-	fs,n = (('{:02}:{:02}:{:02}',6),('{:02}:{:02}',5))[no_secs]
+	ret = (time.localtime, time.gmtime)[utc](secs)
+	fs, n = (('{:02}:{:02}:{:02}', 6), ('{:02}:{:02}', 5))[no_secs]
 	return fs.format(*ret[3:n])
 	return fs.format(*ret[3:n])
 
 
-def get_day_hms(t=None,utc=False):
+def get_day_hms(t=None, utc=False):
 	secs = t or time.time()
 	secs = t or time.time()
-	ret = (time.localtime,time.gmtime)[utc](secs)
+	ret = (time.localtime, time.gmtime)[utc](secs)
 	return '{:04}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*ret[0:6])
 	return '{:04}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*ret[0:6])
 
 
-def do_system(cmd,testing=False,shell=False):
+def do_system(cmd, testing=False, shell=False):
 	if testing:
 	if testing:
 		from mmgen.util import msg
 		from mmgen.util import msg
 		msg("Would execute: '%s'" % cmd)
 		msg("Would execute: '%s'" % cmd)
 		return True
 		return True
 	else:
 	else:
 		import subprocess
 		import subprocess
-		return subprocess.call((cmd if shell else cmd.split()),shell,stderr=subprocess.PIPE)
+		return subprocess.call((cmd if shell else cmd.split()), shell, stderr=subprocess.PIPE)
 
 
-def get_url(url,gzip_ok=False,proxy=None,timeout=60,verbose=False,debug=False):
+def get_url(url, gzip_ok=False, proxy=None, timeout=60, verbose=False, debug=False):
 	if debug:
 	if debug:
 		print('get_url():')
 		print('get_url():')
 		print('  url', url)
 		print('  url', url)
-		print('  gzip_ok:',gzip_ok, 'proxy:',proxy, 'timeout:',timeout, 'verbose:',verbose)
-	import pycurl,io
+		print('  gzip_ok:', gzip_ok, 'proxy:', proxy, 'timeout:', timeout, 'verbose:', verbose)
+	import pycurl, io
 	c = pycurl.Curl()
 	c = pycurl.Curl()
 	c_out = io.StringIO()
 	c_out = io.StringIO()
-	c.setopt(pycurl.WRITEFUNCTION,c_out.write)
-	c.setopt(pycurl.TIMEOUT,timeout)
-	c.setopt(pycurl.FOLLOWLOCATION,True)
-	c.setopt(pycurl.COOKIEFILE,'')
-	c.setopt(pycurl.VERBOSE,verbose)
+	c.setopt(pycurl.WRITEFUNCTION, c_out.write)
+	c.setopt(pycurl.TIMEOUT, timeout)
+	c.setopt(pycurl.FOLLOWLOCATION, True)
+	c.setopt(pycurl.COOKIEFILE, '')
+	c.setopt(pycurl.VERBOSE, verbose)
 	if gzip_ok:
 	if gzip_ok:
-		c.setopt(pycurl.USERAGENT,'Lynx/2.8.9dev.8 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/3.4.9')
+		c.setopt(pycurl.USERAGENT, 'Lynx/2.8.9dev.8 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/3.4.9')
 		c.setopt(pycurl.HTTPHEADER, [
 		c.setopt(pycurl.HTTPHEADER, [
 	'Accept: text/html, text/plain, text/sgml, text/css, application/xhtml+xml, */*;q=0.01',
 	'Accept: text/html, text/plain, text/sgml, text/css, application/xhtml+xml, */*;q=0.01',
 	'Accept-Encoding: gzip',
 	'Accept-Encoding: gzip',
-	'Accept-Language: en']
-		)
+	'Accept-Language: en'])
 	if proxy:
 	if proxy:
-		c.setopt(pycurl.PROXY,proxy)
-	c.setopt(pycurl.URL,url)
+		c.setopt(pycurl.PROXY, proxy)
+	c.setopt(pycurl.URL, url)
 	c.perform()
 	c.perform()
 	text = c_out.getvalue()
 	text = c_out.getvalue()
 	if text[:2] == '\x1f\x8b': # gzip magic number
 	if text[:2] == '\x1f\x8b': # gzip magic number
-		c_out.seek(0,0)
+		c_out.seek(0, 0)
 		import gzip
 		import gzip
 		with gzip.GzipFile(fileobj=c_out) as f:
 		with gzip.GzipFile(fileobj=c_out) as f:
 			text = f.read()
 			text = f.read()
@@ -103,20 +102,19 @@ big_digits = {
 """
 """
 }
 }
 
 
-_bnums_c,_bpunc_c = [[l.strip('\n') + ' ' * (big_digits[m]*big_digits['n'])
+_bnums_c, _bpunc_c = [[l.strip('\n') + ' ' * (big_digits[m]*big_digits['n'])
 	for l in big_digits[k][1:].split('\n')]
 	for l in big_digits[k][1:].split('\n')]
-		for k,m in (('nums','w'),('punc','pw'))]
+		for k, m in (('nums', 'w'), ('punc', 'pw'))]
 
 
-_bnums_n,_bpunc_n = [[[l[0+(j*w):w+(j*w)] for l in i]
-					for j in range(big_digits[n])] for n,w,i in
-						(('n',big_digits['w'],_bnums_c),('pn',big_digits['pw'],_bpunc_c))]
+_bnums_n, _bpunc_n = [[[l[0+(j*w):w+(j*w)] for l in i]
+	for j in range(big_digits[n])] for n, w, i in
+		(('n', big_digits['w'], _bnums_c), ('pn', big_digits['pw'], _bpunc_c))]
 
 
-def display_big_digits(s,pre='',suf=''):
-	s = [int((d,10,11)[(d in '.:')+(d==':')]) for d in s]
+def display_big_digits(s, pre='', suf=''):
+	s = [int((d, 10, 11)[(d in '.:')+(d==':')]) for d in s]
 	return pre + ('\n'+pre).join(
 	return pre + ('\n'+pre).join(
-		[''.join([(_bnums_n+_bpunc_n)[d][l] for d in s]) + suf for l in range(big_digits['h'])]
-	)
+		[''.join([(_bnums_n+_bpunc_n)[d][l] for d in s]) + suf for l in range(big_digits['h'])])
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
 	num = '2345.17'
 	num = '2345.17'
-	print(display_big_digits(num,pre='+ ',suf='  +'))
+	print(display_big_digits(num, pre='+ ', suf='  +'))

+ 32 - 34
mmgen_node_tools/main_addrbal.py

@@ -16,7 +16,7 @@ import sys
 
 
 from mmgen.obj import CoinTxID
 from mmgen.obj import CoinTxID
 from mmgen.cfg import Config
 from mmgen.cfg import Config
-from mmgen.util import msg,Msg,die,suf,make_timestr,async_run
+from mmgen.util import msg, Msg, die, suf, make_timestr, async_run
 from mmgen.color import red
 from mmgen.color import red
 
 
 opts_data = {
 opts_data = {
@@ -32,16 +32,16 @@ opts_data = {
 	}
 	}
 }
 }
 
 
-def do_output(proto,addr_data,blk_hdrs):
+def do_output(proto, addr_data, blk_hdrs):
 
 
 	col1w = len(str(len(addr_data)))
 	col1w = len(str(len(addr_data)))
 	indent = ' ' * (col1w + 2)
 	indent = ' ' * (col1w + 2)
 
 
-	for n,(addr,unspents) in enumerate(addr_data.items(),1):
+	for n, (addr, unspents) in enumerate(addr_data.items(), 1):
 		Msg(f'\n{n:{col1w}}) Address: {addr.hl(addr.view_pref)}')
 		Msg(f'\n{n:{col1w}}) Address: {addr.hl(addr.view_pref)}')
 
 
 		if unspents:
 		if unspents:
-			heights = { u['height'] for u in unspents }
+			heights = {u['height'] for u in unspents}
 			Msg('{}Balance: {}'.format(
 			Msg('{}Balance: {}'.format(
 				indent,
 				indent,
 				sum(proto.coin_amt(u['amount']) for u in unspents).hl2(unit=True, fs='{:,}'))),
 				sum(proto.coin_amt(u['amount']) for u in unspents).hl2(unit=True, fs='{:,}'))),
@@ -50,22 +50,21 @@ def do_output(proto,addr_data,blk_hdrs):
 				red(str(len(unspents))),
 				red(str(len(unspents))),
 				suf(unspents),
 				suf(unspents),
 				red(str(len(heights))),
 				red(str(len(heights))),
-				suf(heights) ))
+				suf(heights)))
 			blk_w = len(str(unspents[-1]['height']))
 			blk_w = len(str(unspents[-1]['height']))
-			fs = '%s{:%s} {:19} {:64} {:4} {}' % (indent,max(5,blk_w))
-			Msg(fs.format('Block','Date','TxID','Vout','   Amount'))
+			fs = '%s{:%s} {:19} {:64} {:4} {}' % (indent, max(5, blk_w))
+			Msg(fs.format('Block', 'Date', 'TxID', 'Vout', '   Amount'))
 			for u in unspents:
 			for u in unspents:
 				Msg(fs.format(
 				Msg(fs.format(
 					u['height'],
 					u['height'],
-					make_timestr( blk_hdrs[u['height']]['time'] ),
+					make_timestr(blk_hdrs[u['height']]['time']),
 					CoinTxID(u['txid']).hl(),
 					CoinTxID(u['txid']).hl(),
 					red(str(u['vout']).rjust(4)),
 					red(str(u['vout']).rjust(4)),
-					proto.coin_amt(u['amount']).fmt(6, color=True, prec=8)
-				))
+					proto.coin_amt(u['amount']).fmt(6, color=True, prec=8)))
 		else:
 		else:
 			Msg(f'{indent}No balance')
 			Msg(f'{indent}No balance')
 
 
-def do_output_tabular(proto,addr_data,blk_hdrs):
+def do_output_tabular(proto, addr_data, blk_hdrs):
 
 
 	col1w = len(str(len(addr_data))) + 1
 	col1w = len(str(len(addr_data))) + 1
 	max_addrw = max(len(addr) for addr in addr_data)
 	max_addrw = max(len(addr) for addr in addr_data)
@@ -75,9 +74,9 @@ def do_output_tabular(proto,addr_data,blk_hdrs):
 	lb_w = max(len(h) for h in lb_heights)
 	lb_w = max(len(h) for h in lb_heights)
 
 
 	fs = (
 	fs = (
-		' {n:>%s} {a} {u} {b:>%s} {t:19}  {B:>%s} {T:19} {A}' % (col1w,max(5,fb_w),max(4,lb_w))
+		' {n:>%s} {a} {u} {b:>%s} {t:19}  {B:>%s} {T:19} {A}' % (col1w, max(5, fb_w), max(4, lb_w))
 			if cfg.first_block else
 			if cfg.first_block else
-		' {n:>%s} {a} {u} {B:>%s} {T:19} {A}' % (col1w,max(4,lb_w)) )
+		' {n:>%s} {a} {u} {B:>%s} {T:19} {A}' % (col1w, max(4, lb_w)))
 
 
 	Msg('\n' + fs.format(
 	Msg('\n' + fs.format(
 		n = '',
 		n = '',
@@ -87,20 +86,19 @@ def do_output_tabular(proto,addr_data,blk_hdrs):
 		t = 'Block',
 		t = 'Block',
 		B = 'Last',
 		B = 'Last',
 		T = 'Block',
 		T = 'Block',
-		A = '     Amount' ))
+		A = '     Amount'))
 
 
-	for n,(addr,unspents) in enumerate(addr_data.items(),1):
+	for n, (addr, unspents) in enumerate(addr_data.items(), 1):
 		if unspents:
 		if unspents:
 			Msg(fs.format(
 			Msg(fs.format(
 				n = str(n) + ')',
 				n = str(n) + ')',
 				a = addr.fmt(addr.view_pref, max_addrw, color=True),
 				a = addr.fmt(addr.view_pref, max_addrw, color=True),
 				u = red(str(len(unspents)).rjust(5)),
 				u = red(str(len(unspents)).rjust(5)),
 				b = unspents[0]['height'],
 				b = unspents[0]['height'],
-				t = make_timestr( blk_hdrs[unspents[0]['height']]['time'] ),
+				t = make_timestr(blk_hdrs[unspents[0]['height']]['time']),
 				B = unspents[-1]['height'],
 				B = unspents[-1]['height'],
-				T = make_timestr( blk_hdrs[unspents[-1]['height']]['time'] ),
-				A = sum(proto.coin_amt(u['amount']) for u in unspents).fmt(7, color=True, prec=8)
-			))
+				T = make_timestr(blk_hdrs[unspents[-1]['height']]['time']),
+				A = sum(proto.coin_amt(u['amount']) for u in unspents).fmt(7, color=True, prec=8)))
 		else:
 		else:
 			Msg(fs.format(
 			Msg(fs.format(
 				n = str(n) + ')',
 				n = str(n) + ')',
@@ -110,61 +108,61 @@ def do_output_tabular(proto,addr_data,blk_hdrs):
 				t = '',
 				t = '',
 				B = '-',
 				B = '-',
 				T = '',
 				T = '',
-				A = '     -' ))
+				A = '     -'))
 
 
 async def main(req_addrs):
 async def main(req_addrs):
 
 
 	proto = cfg._proto
 	proto = cfg._proto
 
 
 	from mmgen.addr import CoinAddr
 	from mmgen.addr import CoinAddr
-	addrs = [CoinAddr(proto,addr) for addr in req_addrs]
+	addrs = [CoinAddr(proto, addr) for addr in req_addrs]
 
 
 	from mmgen.rpc import rpc_init
 	from mmgen.rpc import rpc_init
-	rpc = await rpc_init(cfg,ignore_wallet=True)
+	rpc = await rpc_init(cfg, ignore_wallet=True)
 
 
 	height = await rpc.call('getblockcount')
 	height = await rpc.call('getblockcount')
 	Msg(f'{proto.coin} {proto.network.upper()} [height {height}]')
 	Msg(f'{proto.coin} {proto.network.upper()} [height {height}]')
 
 
 	from mmgen.proto.btc.misc import scantxoutset
 	from mmgen.proto.btc.misc import scantxoutset
-	res = await scantxoutset( cfg, rpc, [f'addr({addr})' for addr in addrs] )
+	res = await scantxoutset(cfg, rpc, [f'addr({addr})' for addr in addrs])
 
 
 	if not res['success']:
 	if not res['success']:
-		die(1,'UTXO scanning failed or was interrupted')
+		die(1, 'UTXO scanning failed or was interrupted')
 	elif not res['unspents']:
 	elif not res['unspents']:
 		msg('Address has no balance' if len(addrs) == 1 else
 		msg('Address has no balance' if len(addrs) == 1 else
-			'Addresses have no balances' )
+			'Addresses have no balances')
 	else:
 	else:
 		addr_data = {k:[] for k in addrs}
 		addr_data = {k:[] for k in addrs}
 
 
 		if 'desc' in res['unspents'][0]:
 		if 'desc' in res['unspents'][0]:
 			import re
 			import re
-			for unspent in sorted(res['unspents'],key=lambda x: x['height']):
-				addr = re.match('addr\((.*?)\)',unspent['desc'])[1]
+			for unspent in sorted(res['unspents'], key=lambda x: x['height']):
+				addr = re.match('addr\((.*?)\)', unspent['desc'])[1]
 				addr_data[addr].append(unspent)
 				addr_data[addr].append(unspent)
 		else:
 		else:
 			from mmgen.proto.btc.tx.base import decodeScriptPubKey
 			from mmgen.proto.btc.tx.base import decodeScriptPubKey
-			for unspent in sorted(res['unspents'],key=lambda x: x['height']):
+			for unspent in sorted(res['unspents'], key=lambda x: x['height']):
 				ds = decodeScriptPubKey(proto, unspent['scriptPubKey'])
 				ds = decodeScriptPubKey(proto, unspent['scriptPubKey'])
 				addr_data[ds.addr].append(unspent)
 				addr_data[ds.addr].append(unspent)
 
 
 		good_addrs = len([v for v in addr_data.values() if v])
 		good_addrs = len([v for v in addr_data.values() if v])
 
 
 		Msg('Total: {} in {} address{}'.format(
 		Msg('Total: {} in {} address{}'.format(
-			proto.coin_amt(res['total_amount']).hl2(unit=True,fs='{:,}'),
+			proto.coin_amt(res['total_amount']).hl2(unit=True, fs='{:,}'),
 			red(str(good_addrs)),
 			red(str(good_addrs)),
-			suf(good_addrs,'es')
-		))
+			suf(good_addrs, 'es')))
 
 
 		blk_heights = {i['height'] for i in res['unspents']}
 		blk_heights = {i['height'] for i in res['unspents']}
 		blk_hashes = await rpc.batch_call('getblockhash', [(h,) for h in blk_heights])
 		blk_hashes = await rpc.batch_call('getblockhash', [(h,) for h in blk_heights])
 		blk_hdrs = await rpc.batch_call('getblockheader', [(H,) for H in blk_hashes])
 		blk_hdrs = await rpc.batch_call('getblockheader', [(H,) for H in blk_hashes])
 
 
-		(do_output_tabular if cfg.tabular else do_output)( proto, addr_data, dict(zip(blk_heights,blk_hdrs)) )
+		(do_output_tabular if cfg.tabular else do_output)(
+			proto, addr_data, dict(zip(blk_heights, blk_hdrs)))
 
 
-cfg = Config( opts_data=opts_data, init_opts={'rpc_backend':'aiohttp'} )
+cfg = Config(opts_data=opts_data, init_opts={'rpc_backend': 'aiohttp'})
 
 
 if len(cfg._args) < 1:
 if len(cfg._args) < 1:
-	die(1,'This command requires at least one coin address argument')
+	die(1, 'This command requires at least one coin address argument')
 
 
 try:
 try:
 	async_run(cfg, main, args=[cfg._args])
 	async_run(cfg, main, args=[cfg._args])

+ 9 - 10
mmgen_node_tools/main_blocks_info.py

@@ -20,9 +20,9 @@
 mmnode-blocks-info: Display information about a block or range of blocks
 mmnode-blocks-info: Display information about a block or range of blocks
 """
 """
 
 
-from mmgen.cfg import gc,Config
-from mmgen.util import async_run,fmt_list
-from .BlocksInfo import BlocksInfo,JSONBlocksInfo
+from mmgen.cfg import gc, Config
+from mmgen.util import async_run, fmt_list
+from .BlocksInfo import BlocksInfo, JSONBlocksInfo
 
 
 opts_data = {
 opts_data = {
 	'sets': [
 	'sets': [
@@ -145,14 +145,13 @@ EXAMPLES:
     $ {p} --rpc-backend=aio -H +1000
     $ {p} --rpc-backend=aio -H +1000
 
 
 This program requires a txindex-enabled daemon for correct operation.
 This program requires a txindex-enabled daemon for correct operation.
-""" },
+"""},
 	'code': {
 	'code': {
-		'notes': lambda cfg,proto,s: s.format(
+		'notes': lambda cfg, proto, s: s.format(
 			I = proto.diff_adjust_interval,
 			I = proto.diff_adjust_interval,
-			F = fmt_list(BlocksInfo.fields,fmt='bare'),
-			S = fmt_list(BlocksInfo.all_stats,fmt='bare'),
-			p = gc.prog_name,
-		)
+			F = fmt_list(BlocksInfo.fields, fmt='bare'),
+			S = fmt_list(BlocksInfo.all_stats, fmt='bare'),
+			p = gc.prog_name)
 	}
 	}
 }
 }
 
 
@@ -172,7 +171,7 @@ async def main():
 	await m.process_blocks()
 	await m.process_blocks()
 
 
 	if m.last:
 	if m.last:
-		for i,sname in enumerate(m.stats):
+		for i, sname in enumerate(m.stats):
 			m.process_stats_pre(i)
 			m.process_stats_pre(i)
 			await m.process_stats(sname)
 			await m.process_stats(sname)
 
 

+ 32 - 33
mmgen_node_tools/main_feeview.py

@@ -21,10 +21,10 @@ mmnode-feeview: Visualize the fee structure of a node’s mempool
 """
 """
 
 
 from mmgen.cfg import Config
 from mmgen.cfg import Config
-from mmgen.util import async_run,die,fmt,make_timestr,check_int_between
-from mmgen.util2 import int2bytespec,parse_bytespec
+from mmgen.util import async_run, die, fmt, make_timestr, check_int_between
+from mmgen.util2 import int2bytespec, parse_bytespec
 
 
-min_prec,max_prec,dfl_prec = (0,6,4)
+min_prec, max_prec, dfl_prec = (0, 6, 4)
 fee_brackets = [
 fee_brackets = [
 	1, 2, 3, 4, 5, 6,
 	1, 2, 3, 4, 5, 6,
 	8, 10, 12, 14, 16, 18,
 	8, 10, 12, 14, 16, 18,
@@ -42,9 +42,9 @@ fee_brackets = [
 
 
 opts_data = {
 opts_data = {
 	'sets': [
 	'sets': [
-		('detail',True,'ranges',True),
-		('detail',True,'show_mb_col',True),
-		('detail',True,'precision',6),
+		('detail', True, 'ranges', True),
+		('detail', True, 'show_mb_col', True),
+		('detail', True, 'precision', 6),
 	],
 	],
 	'text': {
 	'text': {
 		'desc': 'Visualize the fee structure of a node’s mempool',
 		'desc': 'Visualize the fee structure of a node’s mempool',
@@ -83,37 +83,37 @@ cfg = Config(opts_data=opts_data)
 
 
 if cfg.ignore_below:
 if cfg.ignore_below:
 	if cfg.show_empty:
 	if cfg.show_empty:
-		die(1,'Conflicting options: --ignore-below, --show-empty')
+		die(1, 'Conflicting options: --ignore-below, --show-empty')
 	ignore_below = parse_bytespec(cfg.ignore_below)
 	ignore_below = parse_bytespec(cfg.ignore_below)
 
 
 precision = (
 precision = (
 	check_int_between(cfg.precision, min_prec, max_prec, desc='--precision arg')
 	check_int_between(cfg.precision, min_prec, max_prec, desc='--precision arg')
-	if cfg.precision else dfl_prec )
+	if cfg.precision else dfl_prec)
 
 
 from mmgen.term import get_terminal_size
 from mmgen.term import get_terminal_size
 width = cfg.columns or get_terminal_size().width
 width = cfg.columns or get_terminal_size().width
 
 
 class fee_bracket:
 class fee_bracket:
-	def __init__(self,top,bottom):
+	def __init__(self, top, bottom):
 		self.top = top
 		self.top = top
 		self.bottom = bottom
 		self.bottom = bottom
 		self.tx_bytes = 0
 		self.tx_bytes = 0
 		self.tx_bytes_cum = 0
 		self.tx_bytes_cum = 0
 		self.skip = False
 		self.skip = False
 
 
-def log(data,fn):
+def log(data, fn):
 	import json
 	import json
 	from mmgen.rpc.util import json_encoder
 	from mmgen.rpc.util import json_encoder
 	from mmgen.fileutil import write_data_to_file
 	from mmgen.fileutil import write_data_to_file
 	write_data_to_file(
 	write_data_to_file(
 		cfg     = cfg,
 		cfg     = cfg,
 		outfile = fn,
 		outfile = fn,
-		data = json.dumps(data,cls=json_encoder,sort_keys=True,indent=4),
+		data = json.dumps(data, cls=json_encoder, sort_keys=True, indent=4),
 		desc = 'mempool',
 		desc = 'mempool',
-		ask_overwrite = False )
+		ask_overwrite = False)
 
 
-def create_data(coin_amt,mempool):
-	out = [fee_bracket(fee_brackets[i],fee_brackets[i-1] if i else 0) for i in range(len(fee_brackets))]
+def create_data(coin_amt, mempool):
+	out = [fee_bracket(fee_brackets[i], fee_brackets[i-1] if i else 0) for i in range(len(fee_brackets))]
 
 
 	# populate fee brackets:
 	# populate fee brackets:
 	size_key = 'size' if proto.coin == 'BCH' else 'vsize'
 	size_key = 'size' if proto.coin == 'BCH' else 'vsize'
@@ -143,7 +143,7 @@ def create_data(coin_amt,mempool):
 
 
 	return out
 	return out
 
 
-def gen_header(host,mempool,blockcount):
+def gen_header(host, mempool, blockcount):
 
 
 	yield fmt(f"""
 	yield fmt(f"""
 		Mempool Fee Structure
 		Mempool Fee Structure
@@ -159,27 +159,26 @@ def gen_header(host,mempool,blockcount):
 	elif cfg.ignore_below:
 	elif cfg.ignore_below:
 		yield 'Ignoring fee brackets with less than {:,} bytes ({})'.format(
 		yield 'Ignoring fee brackets with less than {:,} bytes ({})'.format(
 				ignore_below,
 				ignore_below,
-				int2bytespec(ignore_below,'MB','0.6',strip=True,add_space=True),
-			)
+				int2bytespec(ignore_below, 'MB', '0.6', strip=True, add_space=True))
 
 
 	if cfg.include_current:
 	if cfg.include_current:
 		yield 'Including transactions in current fee bracket in Total MB amounts'
 		yield 'Including transactions in current fee bracket in Total MB amounts'
 
 
 def fmt_mb(n):
 def fmt_mb(n):
-	return int2bytespec(n,'MB',f'0.{precision}',print_sym=False)
+	return int2bytespec(n, 'MB', f'0.{precision}', print_sym=False)
 
 
 def gen_body(data):
 def gen_body(data):
-	tx_bytes_max = max((i.tx_bytes for i in data),default=0)
-	top_max = max((i.top for i in data),default=0)
-	bot_max = max((i.bottom for i in data),default=0)
-	col1_w = max(len(f'{bot_max}-{top_max}') if cfg.ranges else len(f'{top_max}'),6)
+	tx_bytes_max = max((i.tx_bytes for i in data), default=0)
+	top_max = max((i.top for i in data), default=0)
+	bot_max = max((i.bottom for i in data), default=0)
+	col1_w = max(len(f'{bot_max}-{top_max}') if cfg.ranges else len(f'{top_max}'), 6)
 	col2_w = len(fmt_mb(tx_bytes_max)) if cfg.show_mb_col else 0
 	col2_w = len(fmt_mb(tx_bytes_max)) if cfg.show_mb_col else 0
 	col3_w = len(fmt_mb(data[-1].tx_bytes_cum)) if data else 0
 	col3_w = len(fmt_mb(data[-1].tx_bytes_cum)) if data else 0
 	col4_w = width - col1_w - col2_w - col3_w - (4 if col2_w else 3)
 	col4_w = width - col1_w - col2_w - col3_w - (4 if col2_w else 3)
 	if cfg.show_mb_col:
 	if cfg.show_mb_col:
-		fs = '{a:<%i} {b:>%i} {c:>%i} {d}' % (col1_w,col2_w,col3_w)
+		fs = '{a:<%i} {b:>%i} {c:>%i} {d}' % (col1_w, col2_w, col3_w)
 	else:
 	else:
-		fs = '{a:<%i} {c:>%i} {d}' % (col1_w,col3_w)
+		fs = '{a:<%i} {c:>%i} {d}' % (col1_w, col3_w)
 
 
 	yield fs.format(a='',      b='',                  c=f'{"Total":<{col3_w}}', d='')
 	yield fs.format(a='',      b='',                  c=f'{"Total":<{col3_w}}', d='')
 	yield fs.format(a='sat/B', b=f'{"MB":<{col2_w}}', c=f'{"MB":<{col3_w}}',    d='')
 	yield fs.format(a='sat/B', b=f'{"MB":<{col2_w}}', c=f'{"MB":<{col3_w}}',    d='')
@@ -188,16 +187,16 @@ def gen_body(data):
 		if not i.skip:
 		if not i.skip:
 			cum_bytes = i.tx_bytes_cum + i.tx_bytes if cfg.include_current else i.tx_bytes_cum
 			cum_bytes = i.tx_bytes_cum + i.tx_bytes if cfg.include_current else i.tx_bytes_cum
 			yield fs.format(
 			yield fs.format(
-				a = '{}-{}'.format(i.bottom,i.top) if cfg.ranges else i.top,
+				a = '{}-{}'.format(i.bottom, i.top) if cfg.ranges else i.top,
 				b = fmt_mb(i.tx_bytes),
 				b = fmt_mb(i.tx_bytes),
 				c = fmt_mb(cum_bytes),
 				c = fmt_mb(cum_bytes),
-				d = '-' * int(col4_w * ( i.tx_bytes / tx_bytes_max )) )
+				d = '-' * int(col4_w * (i.tx_bytes / tx_bytes_max)))
 
 
 	yield fs.format(
 	yield fs.format(
 		a = 'TOTAL',
 		a = 'TOTAL',
 		b = '',
 		b = '',
 		c = fmt_mb(data[-1].tx_bytes_cum + data[-1].tx_bytes if data else 0),
 		c = fmt_mb(data[-1].tx_bytes_cum + data[-1].tx_bytes if data else 0),
-		d = '' )
+		d = '')
 
 
 async def main():
 async def main():
 
 
@@ -205,19 +204,19 @@ async def main():
 	proto = cfg._proto
 	proto = cfg._proto
 
 
 	from mmgen.rpc import rpc_init
 	from mmgen.rpc import rpc_init
-	c = await rpc_init(cfg,ignore_wallet=True)
+	c = await rpc_init(cfg, ignore_wallet=True)
 
 
-	mempool = await c.call('getrawmempool',True)
+	mempool = await c.call('getrawmempool', True)
 
 
 	if cfg.log:
 	if cfg.log:
-		log(mempool,'mempool.json')
+		log(mempool, 'mempool.json')
 
 
-	data = create_data(proto.coin_amt,mempool)
+	data = create_data(proto.coin_amt, mempool)
 	cfg._util.stdout_or_pager(
 	cfg._util.stdout_or_pager(
 		'\n'.join(gen_header(
 		'\n'.join(gen_header(
 			c.host,
 			c.host,
 			mempool,
 			mempool,
-			await c.call('getblockcount') )) + '\n\n' +
-		'\n'.join(gen_body(data)) + '\n' )
+			await c.call('getblockcount'))) + '\n\n' +
+		'\n'.join(gen_body(data)) + '\n')
 
 
 async_run(cfg, main)
 async_run(cfg, main)

+ 25 - 31
mmgen_node_tools/main_halving_calculator.py

@@ -28,7 +28,7 @@ from mmgen.util import async_run
 bdr_proj = 9.95
 bdr_proj = 9.95
 
 
 opts_data = {
 opts_data = {
-	'sets': [('mined',True,'list',True)],
+	'sets': [('mined', True, 'list', True)],
 	'text': {
 	'text': {
 		'desc': 'Estimate date(s) of future block subsidy halving(s)',
 		'desc': 'Estimate date(s) of future block subsidy halving(s)',
 		'usage':'[opts]',
 		'usage':'[opts]',
@@ -41,7 +41,7 @@ opts_data = {
                     {bdr_proj:.5f} min)
                     {bdr_proj:.5f} min)
 -s, --sample-size=N Block range to calculate block discovery interval for next
 -s, --sample-size=N Block range to calculate block discovery interval for next
                     halving estimate (default: dynamically calculated)
                     halving estimate (default: dynamically calculated)
-""" }
+"""}
 }
 }
 
 
 cfg = Config(opts_data=opts_data)
 cfg = Config(opts_data=opts_data)
@@ -53,14 +53,14 @@ def date(t):
 	return '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*time.gmtime(t)[:6])
 	return '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*time.gmtime(t)[:6])
 
 
 def dhms(t):
 def dhms(t):
-	t,neg = (-t,'-') if t < 0 else (t,' ')
+	t, neg = (-t, '-') if t < 0 else (t, ' ')
 	return f'{neg}{t//60//60//24} days, {t//60//60%24:02}:{t//60%60:02}:{t%60:02} h/m/s'
 	return f'{neg}{t//60//60//24} days, {t//60//60%24:02}:{t//60%60:02}:{t%60:02} h/m/s'
 
 
 def time_diff_warning(t_diff):
 def time_diff_warning(t_diff):
 	if abs(t_diff) > 60*60:
 	if abs(t_diff) > 60*60:
 		print('Warning: block tip time is {} {} clock time!'.format(
 		print('Warning: block tip time is {} {} clock time!'.format(
 			dhms(abs(t_diff)),
 			dhms(abs(t_diff)),
-			('behind','ahead of')[t_diff<0]))
+			('behind', 'ahead of')[t_diff<0]))
 
 
 async def main():
 async def main():
 
 
@@ -72,9 +72,9 @@ async def main():
 	tip = await c.call('getblockcount')
 	tip = await c.call('getblockcount')
 	assert tip > 1, 'block tip must be > 1'
 	assert tip > 1, 'block tip must be > 1'
 	remaining = proto.halving_interval - tip % proto.halving_interval
 	remaining = proto.halving_interval - tip % proto.halving_interval
-	sample_size = int(cfg.sample_size) if cfg.sample_size else min(tip-1,max(remaining,144))
+	sample_size = int(cfg.sample_size) if cfg.sample_size else min(tip-1, max(remaining, 144))
 
 
-	cur,old = await c.gathered_call('getblockstats',((tip,),(tip - sample_size,)))
+	cur, old = await c.gathered_call('getblockstats', ((tip,), (tip - sample_size,)))
 
 
 	clock_time = int(time.time())
 	clock_time = int(time.time())
 	time_diff_warning(clock_time - cur['time'])
 	time_diff_warning(clock_time - cur['time'])
@@ -98,8 +98,7 @@ async def main():
 			f'Current block discovery interval (over last {sample_size} blocks): {bdr/60:0.2f} min\n\n'
 			f'Current block discovery interval (over last {sample_size} blocks): {bdr/60:0.2f} min\n\n'
 			f'Current clock time (UTC):  {date(clock_time)}\n'
 			f'Current clock time (UTC):  {date(clock_time)}\n'
 			f'Est. halving date (UTC):   {date(t_next)}\n'
 			f'Est. halving date (UTC):   {date(t_next)}\n'
-			f'Est. time until halving:  {dhms(cur["time"] + t_rem - clock_time)}'
-		)
+			f'Est. time until halving:   {dhms(cur["time"] + t_rem - clock_time)}')
 
 
 	async def print_halvings():
 	async def print_halvings():
 		halving_blocknums = [i*proto.halving_interval for i in range(proto.max_halvings+1)][1:]
 		halving_blocknums = [i*proto.halving_interval for i in range(proto.max_halvings+1)][1:]
@@ -108,13 +107,13 @@ async def main():
 		nhist = len(hist_halvings)
 		nhist = len(hist_halvings)
 		nSubsidy = int(proto.start_subsidy / proto.coin_amt.satoshi)
 		nSubsidy = int(proto.start_subsidy / proto.coin_amt.satoshi)
 
 
-		block0_hash = await c.call('getblockhash',0)
-		block0_date = (await c.call('getblock',block0_hash))['time']
+		block0_hash = await c.call('getblockhash', 0)
+		block0_date = (await c.call('getblock', block0_hash))['time']
 
 
 		def gen_data():
 		def gen_data():
 			total_mined = 0
 			total_mined = 0
 			date = block0_date
 			date = block0_date
-			for n,blk in enumerate(halving_blocknums):
+			for n, blk in enumerate(halving_blocknums):
 				mined = (nSubsidy >> n) * proto.halving_interval
 				mined = (nSubsidy >> n) * proto.halving_interval
 				if n == 0:
 				if n == 0:
 					mined -= nSubsidy # subtract unspendable genesis block subsidy
 					mined -= nSubsidy # subtract unspendable genesis block subsidy
@@ -123,13 +122,11 @@ async def main():
 				bdi = (
 				bdi = (
 					(hist_halvings[n]['time'] - date) / (proto.halving_interval * 60) if n < nhist
 					(hist_halvings[n]['time'] - date) / (proto.halving_interval * 60) if n < nhist
 					else bdr/60 if n == nhist
 					else bdr/60 if n == nhist
-					else bdr_proj
-				)
+					else bdr_proj)
 				date = (
 				date = (
 					hist_halvings[n]['time'] if n < nhist
 					hist_halvings[n]['time'] if n < nhist
-					else t_next + int((n - nhist) * halving_secs)
-				)
-				yield ( n, sub, blk, mined, total_mined, bdi, date )
+					else t_next + int((n - nhist) * halving_secs))
+				yield (n, sub, blk, mined, total_mined, bdi, date)
 				if sub == 0:
 				if sub == 0:
 					break
 					break
 
 
@@ -150,8 +147,7 @@ async def main():
 				e = 'BDI (mins)',
 				e = 'BDI (mins)',
 				f = 'SUBSIDY ({proto.coin})',
 				f = 'SUBSIDY ({proto.coin})',
 				g = f'MINED ({proto.coin})',
 				g = f'MINED ({proto.coin})',
-				h = f'TOTAL MINED ({proto.coin})'
-			)
+				h = f'TOTAL MINED ({proto.coin})')
 			+ '\n'
 			+ '\n'
 			+ fs.format(
 			+ fs.format(
 				a = '-' * 7,
 				a = '-' * 7,
@@ -159,22 +155,20 @@ async def main():
 				c = '-' * 19,
 				c = '-' * 19,
 				d = '-' * 2,
 				d = '-' * 2,
 				e = '-' * 10,
 				e = '-' * 10,
-				f = '-' * 13,
+				f = '-' * 17,
 				g = '-' * 17,
 				g = '-' * 17,
-				h = '-' * 17
-			)
+				h = '-' * 17)
 			+ '\n'
 			+ '\n'
 			+ '\n'.join(fs.format(
 			+ '\n'.join(fs.format(
-							a = n + 1,
-							b = blk,
-							c = date(t),
-							d = ' P' if n > nhist else '' if n < nhist else ' E',
-							e = f'{bdr:8.5f}',
-							f = proto.coin_amt(sub, from_unit='satoshi').fmt(2, prec=8),
-							g = proto.coin_amt(mined, from_unit='satoshi').fmt(8, prec=8),
-							h = proto.coin_amt(total_mined, from_unit='satoshi').fmt(8, prec=8)
-						) for n, sub, blk, mined, total_mined, bdr, t in gen_data())
-		)
+				a = n + 1,
+				b = blk,
+				c = date(t),
+				d = ' P' if n > nhist else '' if n < nhist else ' E',
+				e = f'{bdr:8.5f}',
+				f = proto.coin_amt(sub, from_unit='satoshi').fmt(2, prec=8),
+				g = proto.coin_amt(mined, from_unit='satoshi').fmt(8, prec=8),
+				h = proto.coin_amt(total_mined, from_unit='satoshi').fmt(8, prec=8)
+			) for n, sub, blk, mined, total_mined, bdr, t in gen_data()))
 
 
 	if cfg.list:
 	if cfg.list:
 		await print_halvings()
 		await print_halvings()

+ 10 - 11
mmgen_node_tools/main_netrate.py

@@ -20,7 +20,7 @@
 mmnode-netrate: Bitcoin daemon network rate monitor
 mmnode-netrate: Bitcoin daemon network rate monitor
 """
 """
 
 
-import sys,time
+import sys, time
 
 
 from mmgen.cfg import Config
 from mmgen.cfg import Config
 from mmgen.util import async_run
 from mmgen.util import async_run
@@ -32,39 +32,38 @@ opts_data = {
 		'options': """
 		'options': """
 -h, --help      Print this help message
 -h, --help      Print this help message
 --, --longhelp  Print help message for long options (common options)
 --, --longhelp  Print help message for long options (common options)
-"""
-	}
+"""}
 }
 }
 
 
 cfg = Config(opts_data=opts_data)
 cfg = Config(opts_data=opts_data)
 
 
-ERASE_LINE,CUR_UP = '\033[K','\033[1A'
+ERASE_LINE, CUR_UP = '\033[K', '\033[1A'
 
 
 async def main():
 async def main():
 
 
 	from mmgen.rpc import rpc_init
 	from mmgen.rpc import rpc_init
-	c = await rpc_init(cfg,ignore_wallet=True)
+	c = await rpc_init(cfg, ignore_wallet=True)
 
 
 	async def get_data():
 	async def get_data():
 		d = await c.call('getnettotals')
 		d = await c.call('getnettotals')
-		return [float(e) for e in (d['totalbytesrecv'],d['totalbytessent'],d['timemillis'])]
+		return [float(e) for e in (d['totalbytesrecv'], d['totalbytessent'], d['timemillis'])]
 
 
-	rs,ss,ts = (None,None,None)
+	rs, ss, ts = (None, None, None)
 	while True:
 	while True:
-		r,s,t = await get_data()
+		r, s, t = await get_data()
 
 
 		if rs is not None:
 		if rs is not None:
 			sys.stderr.write(
 			sys.stderr.write(
 				'\rrcvd: {:9.2f} kB/s\nsent: {:9.2f} kB/s '.format(
 				'\rrcvd: {:9.2f} kB/s\nsent: {:9.2f} kB/s '.format(
 					(r-rs)/(t-ts),
 					(r-rs)/(t-ts),
-					(s-ss)/(t-ts) ))
+					(s-ss)/(t-ts)))
 
 
 		time.sleep(2)
 		time.sleep(2)
 
 
 		if rs is not None:
 		if rs is not None:
-			sys.stderr.write('{}{}{}'.format(ERASE_LINE,CUR_UP,ERASE_LINE))
+			sys.stderr.write('{}{}{}'.format(ERASE_LINE, CUR_UP, ERASE_LINE))
 
 
-		rs,ss,ts = (r,s,t)
+		rs, ss, ts = (r, s, t)
 
 
 try:
 try:
 	async_run(cfg, main)
 	async_run(cfg, main)

+ 3 - 4
mmgen_node_tools/main_peerblocks.py

@@ -27,8 +27,7 @@ opts_data = {
 		'options': """
 		'options': """
 -h, --help      Print this help message
 -h, --help      Print this help message
 --, --longhelp  Print help message for long options (common options)
 --, --longhelp  Print help message for long options (common options)
-"""
-	}
+"""}
 }
 }
 
 
 from mmgen.cfg import Config
 from mmgen.cfg import Config
@@ -37,9 +36,9 @@ cfg = Config(opts_data=opts_data)
 async def main():
 async def main():
 
 
 	from mmgen.rpc import rpc_init
 	from mmgen.rpc import rpc_init
-	rpc = await rpc_init(cfg,ignore_wallet=True)
+	rpc = await rpc_init(cfg, ignore_wallet=True)
 
 
-	from .PeerBlocks import BlocksDisplay,PeersDisplay
+	from .PeerBlocks import BlocksDisplay, PeersDisplay
 	blocks = BlocksDisplay(cfg)
 	blocks = BlocksDisplay(cfg)
 	peers = PeersDisplay(cfg)
 	peers = PeersDisplay(cfg)
 
 

+ 10 - 13
mmgen_node_tools/main_ticker.py

@@ -208,29 +208,26 @@ Customize output by editing the file
 
 
 To add a portfolio, edit the file
 To add a portfolio, edit the file
     ~/{pf_cfg}
     ~/{pf_cfg}
-"""
-	},
+"""},
 	'code': {
 	'code': {
 		'options': lambda s: s.format(
 		'options': lambda s: s.format(
-			dfl_cachedir = os.path.relpath(dfl_cachedir,start=homedir),
-			ds           = fmt_dict(DataSource.get_sources(),fmt='equal_compact'),
+			dfl_cachedir = os.path.relpath(dfl_cachedir, start=homedir),
+			ds           = fmt_dict(DataSource.get_sources(), fmt='equal_compact'),
 			al           = DataSource.coinpaprika.dfl_asset_limit,
 			al           = DataSource.coinpaprika.dfl_asset_limit,
-			pc           = fmt_list(Ticker.percent_cols,fmt='bare'),
-		),
+			pc           = fmt_list(Ticker.percent_cols, fmt='bare')),
 		'notes': lambda s: s.format(
 		'notes': lambda s: s.format(
-			assets = fmt_list(assets_list_gen(cfg_in),fmt='col',indent='  '),
-			cfg    = os.path.relpath(cfg_in.cfg_file,start=homedir),
-			pf_cfg = os.path.relpath(cfg_in.portfolio_file,start=homedir),
+			assets = fmt_list(assets_list_gen(cfg_in), fmt='col', indent='  '),
+			cfg    = os.path.relpath(cfg_in.cfg_file, start=homedir),
+			pf_cfg = os.path.relpath(cfg_in.portfolio_file, start=homedir),
 			al     = DataSource.coinpaprika.dfl_asset_limit,
 			al     = DataSource.coinpaprika.dfl_asset_limit,
 			cc     = src_cls['cc'](),
 			cc     = src_cls['cc'](),
-			fi     = src_cls['fi'](),
-		)
+			fi     = src_cls['fi']())
 	}
 	}
 }
 }
 
 
 import os
 import os
 
 
-from mmgen.util import fmt_list,fmt_dict
+from mmgen.util import fmt_list, fmt_dict
 from mmgen.cfg import Config
 from mmgen.cfg import Config
 from . import Ticker
 from . import Ticker
 
 
@@ -238,7 +235,7 @@ gcfg = Config(opts_data=opts_data, caller_post_init=True)
 
 
 Ticker.make_cfg(gcfg)
 Ticker.make_cfg(gcfg)
 
 
-from .Ticker import dfl_cachedir,homedir,DataSource,assets_list_gen,cfg_in,src_cls
+from .Ticker import dfl_cachedir, homedir, DataSource, assets_list_gen, cfg_in, src_cls
 
 
 gcfg._post_init()
 gcfg._post_init()
 
 

+ 7 - 10
mmgen_node_tools/main_txfind.py

@@ -23,7 +23,7 @@ mmnode-txfind: Find a transaction in the blockchain or mempool
 import sys
 import sys
 
 
 from mmgen.cfg import Config
 from mmgen.cfg import Config
-from mmgen.util import msg,Msg,die,is_hex_str,async_run
+from mmgen.util import msg, Msg, die, is_hex_str, async_run
 
 
 opts_data = {
 opts_data = {
 	'text': {
 	'text': {
@@ -48,29 +48,26 @@ msg_data = {
 	'normal': {
 	'normal': {
 		'none':  'Transaction not found in blockchain or mempool',
 		'none':  'Transaction not found in blockchain or mempool',
 		'block': 'Transaction is in block {b} ({c} confirmations)',
 		'block': 'Transaction is in block {b} ({c} confirmations)',
-		'mem':   'Transaction is in mempool',
-	},
+		'mem':   'Transaction is in mempool'},
 	'quiet': {
 	'quiet': {
 		'none':  'None',
 		'none':  'None',
 		'block': '{b} {c}',
 		'block': '{b} {c}',
-		'mem':   'mempool',
-	}
-}
+		'mem':   'mempool'}}
 
 
 async def main(txid):
 async def main(txid):
 	if len(txid) != 64 or not is_hex_str(txid):
 	if len(txid) != 64 or not is_hex_str(txid):
-		die(2,f'{txid}: invalid transaction ID')
+		die(2, f'{txid}: invalid transaction ID')
 
 
 	if cfg.verbose:
 	if cfg.verbose:
 		msg(f'TxID: {txid}')
 		msg(f'TxID: {txid}')
 
 
 	from mmgen.rpc import rpc_init
 	from mmgen.rpc import rpc_init
-	c = await rpc_init(cfg,ignore_wallet=True)
+	c = await rpc_init(cfg, ignore_wallet=True)
 
 
 	exitval = 0
 	exitval = 0
 	try:
 	try:
 		tip1 = await c.call('getblockcount')
 		tip1 = await c.call('getblockcount')
-		ret = await c.call('getrawtransaction',txid,True)
+		ret = await c.call('getrawtransaction', txid, True)
 		tip2 = await c.call('getblockcount')
 		tip2 = await c.call('getblockcount')
 	except:
 	except:
 		Msg('\r' + msgs['none'])
 		Msg('\r' + msgs['none'])
@@ -90,6 +87,6 @@ cfg = Config(opts_data=opts_data)
 msgs = msg_data['quiet' if cfg.quiet else 'normal']
 msgs = msg_data['quiet' if cfg.quiet else 'normal']
 
 
 if len(cfg._args) != 1:
 if len(cfg._args) != 1:
-	die(1,'One transaction ID must be specified')
+	die(1, 'One transaction ID must be specified')
 
 
 sys.exit(async_run(cfg, main, args=[cfg._args[0]]))
 sys.exit(async_run(cfg, main, args=[cfg._args[0]]))

+ 4 - 4
test/cmdtest_d/regtest.py

@@ -335,19 +335,19 @@ class CmdTestRegtest(CmdTestBase):
 			us = await r.rpc_call('listunspent',wallet='miner')
 			us = await r.rpc_call('listunspent',wallet='miner')
 			tx_input = us[7] # 25 BTC in coinbase -- us[0] could have < 25 BTC
 			tx_input = us[7] # 25 BTC in coinbase -- us[0] could have < 25 BTC
 			fee = self.proto.coin_amt('0.001')
 			fee = self.proto.coin_amt('0.001')
-			outputs = {p.addr:tx1_amt for p in pairs[:nTxs]}
+			outputs = {p.addr: tx1_amt for p in pairs[:nTxs]}
 			outputs.update({burn_addr: self.proto.coin_amt(tx_input['amount']) - (tx1_amt*nTxs) - fee})
 			outputs.update({burn_addr: self.proto.coin_amt(tx_input['amount']) - (tx1_amt*nTxs) - fee})
 			return await do_tx(
 			return await do_tx(
-				[{ 'txid': tx_input['txid'], 'vout': 0 }],
+				[{'txid': tx_input['txid'], 'vout': 0}],
 				outputs,
 				outputs,
 				await r.miner_wif)
 				await r.miner_wif)
 
 
 		async def do_tx2(tx,pairno):
 		async def do_tx2(tx,pairno):
 			fee = self.proto.coin_amt(fees[pairno], from_decimal=True)
 			fee = self.proto.coin_amt(fees[pairno], from_decimal=True)
-			outputs = {p.addr:tx2_amt for p in pairs}
+			outputs = {p.addr: tx2_amt for p in pairs}
 			outputs.update({burn_addr: tx1_amt - (tx2_amt*len(pairs)) - fee})
 			outputs.update({burn_addr: tx1_amt - (tx2_amt*len(pairs)) - fee})
 			return await do_tx(
 			return await do_tx(
-				[{ 'txid': tx['txid'], 'vout': pairno }],
+				[{'txid': tx['txid'], 'vout': pairno}],
 				outputs,
 				outputs,
 				pairs[pairno].wif )
 				pairs[pairno].wif )
 
 

+ 3 - 5
test/overlay/fakemods/mmgen_node_tools/PeerBlocks.py

@@ -294,15 +294,14 @@ class fake_data:
 		20 7303 7307 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225
 		20 7303 7307 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225
 		21 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225 7317 7386
 		21 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225 7317 7386
 		22 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225 7317 7386 7398 7409
 		22 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225 7317 7386 7398 7409
-	"""
-	}
+	"""}
 
 
 	def make_data():
 	def make_data():
 
 
 		def gen_address_data():
 		def gen_address_data():
 			for line in fake_data.addresses.strip().split('\n'):
 			for line in fake_data.addresses.strip().split('\n'):
 				data = line.split(maxsplit=2)
 				data = line.split(maxsplit=2)
-				yield (data[0], {k:v for k,v in zip(('id','addr','subver'),data)})
+				yield (data[0], {k: v for k, v in zip(('id', 'addr', 'subver'), data)})
 
 
 		def gen_iterations_data():
 		def gen_iterations_data():
 			for line in fake_data.iterations.strip().split('\n'):
 			for line in fake_data.iterations.strip().split('\n'):
@@ -320,8 +319,7 @@ class fake_data:
 				'id': int(d['id']),
 				'id': int(d['id']),
 				'addr': d['addr'],
 				'addr': d['addr'],
 				'subver': d['subver'],
 				'subver': d['subver'],
-				'inflight': [int(n)+830000 for n in blocks[iter_no]],
-			}
+				'inflight': [int(n)+830000 for n in blocks[iter_no]]}
 
 
 		def gen_data():
 		def gen_data():
 			for iter_no in iterations_data:
 			for iter_no in iterations_data:

Some files were not shown because too many files changed in this diff