From 30d8a4a8717716a1d3ee2fad7ea74e2b8b7e4264 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 28 Mar 2023 18:16:33 +0000 Subject: [PATCH] update for MMGen v13.3.dev42 --- mmgen_node_tools/BlocksInfo.py | 38 +++++------ mmgen_node_tools/PeerBlocks.py | 9 ++- mmgen_node_tools/PollDisplay.py | 3 +- mmgen_node_tools/Ticker.py | 76 ++++++++++----------- mmgen_node_tools/data/version | 2 +- mmgen_node_tools/main_addrbal.py | 17 +++-- mmgen_node_tools/main_blocks_info.py | 19 +++--- mmgen_node_tools/main_feeview.py | 44 ++++++------ mmgen_node_tools/main_halving_calculator.py | 17 +++-- mmgen_node_tools/main_netrate.py | 7 +- mmgen_node_tools/main_peerblocks.py | 13 ++-- mmgen_node_tools/main_ticker.py | 9 ++- mmgen_node_tools/main_txfind.py | 15 ++-- setup.cfg | 2 +- test/test_py_d/ts_main.py | 2 +- test/test_py_d/ts_misc.py | 4 +- test/test_py_d/ts_regtest.py | 18 +++-- test/unit_tests_d/ut_BlocksInfo.py | 9 ++- 18 files changed, 147 insertions(+), 157 deletions(-) diff --git a/mmgen_node_tools/BlocksInfo.py b/mmgen_node_tools/BlocksInfo.py index 27dfa08..70d9821 100755 --- a/mmgen_node_tools/BlocksInfo.py +++ b/mmgen_node_tools/BlocksInfo.py @@ -109,7 +109,7 @@ class BlocksInfo: def parse_cslist(cls,uarg,full_set,dfl_set,desc): def make_list(m,func): - groups_lc = [set(e.lower() for e in g.split(',')) for g in m.groups()] + groups_lc = [set(e.lower() for e in gi.split(',')) for gi in m.groups()] for group in groups_lc: for e in group: if e not in full_set_lc: @@ -135,7 +135,7 @@ class BlocksInfo: else: die(1,f'{uarg}: invalid parameter') - def __init__(self,cmd_args,opt,rpc): + def __init__(self,cfg,cmd_args,rpc): def parse_cs_uarg(uarg,full_set,dfl_set,desc): return ( @@ -144,10 +144,10 @@ class BlocksInfo: ) def get_fields(): - return parse_cs_uarg(opt.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(): - return parse_cs_uarg(opt.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) if not cmd_args: @@ -163,8 +163,8 @@ class BlocksInfo: else: return ([self.conv_blkspec(a) for a in cmd_args],None,None,None) + self.cfg = cfg self.rpc = rpc - self.opt = opt self.tip = rpc.blockcount from_satoshi = self.rpc.proto.coin_amt.satoshi @@ -198,7 +198,7 @@ class BlocksInfo: 'di': lambda arg: '{:.2e}'.format(arg), } - if g.coin == 'BCH': + if self.cfg.coin == 'BCH': self.fmt_funcs.update({ 'su': lambda arg: str(arg).rstrip('0').rstrip('.'), 'fe': lambda arg: str(int(arg * to_satoshi)), @@ -206,26 +206,26 @@ class BlocksInfo: }) self.fnames = tuple( - [f for f in self.fields if self.fields[f].src == 'bh' or f == 'interval'] if opt.header_info else - get_fields() if opt.fields else + [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 opt.miner_info and 'miner' not in self.fnames: + if self.cfg.miner_info and 'miner' not in self.fnames: self.fnames += ('miner',) - self.stats = get_stats() if opt.stats else self.dfl_stats + self.stats = get_stats() if self.cfg.stats else self.dfl_stats # Display diff stats by default only if user-requested range ends with chain tip - if 'diff' in self.stats and not opt.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') - if {'avg','col_avg'} <= set(self.stats) and opt.stats_only: + if {'avg','col_avg'} <= set(self.stats) and self.cfg.stats_only: self.stats.remove('col_avg') if {'avg','mini_avg'} <= set(self.stats): self.stats.remove('mini_avg') - if opt.full_stats: + if self.cfg.full_stats: 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 ) else: @@ -397,7 +397,7 @@ class BlocksInfo: self.t_cur = self.prev_hdrs[n]['time'] ret = await self.process_block(self.hdrs[n]) self.res.append(ret) - if self.fnames and not self.opt.stats_only: + if self.fnames and not self.cfg.stats_only: self.output_block(ret,n) def output_block(self,data,n): @@ -447,7 +447,7 @@ class BlocksInfo: return '---' else: cb = bytes.fromhex(bd['vin'][0]['coinbase']) - if self.opt.raw_miner_info: + if self.cfg.raw_miner_info: return repr(cb) else: trmap_in = { @@ -670,7 +670,7 @@ class BlocksInfo: return ( sname, (d.hdr,) + tuple(gen()) ) def process_stats_pre(self,i): - if (self.fnames and not self.opt.stats_only) or i != 0: + if (self.fnames and not self.cfg.stats_only) or i != 0: Msg('') def finalize_output(self): pass @@ -707,9 +707,9 @@ class BlocksInfo: class JSONBlocksInfo(BlocksInfo): - def __init__(self,cmd_args,opt,rpc): - super().__init__(cmd_args,opt,rpc) - if opt.json_raw: + def __init__(self,cfg,cmd_args,opt,rpc): + super().__init__(cfg,cmd_args,opt,rpc) + if self.cfg.json_raw: self.output_block = self.output_block_raw self.fmt_stat_item = self.fmt_stat_item_raw Msg_r('{') diff --git a/mmgen_node_tools/PeerBlocks.py b/mmgen_node_tools/PeerBlocks.py index 6df9894..0b386fb 100755 --- a/mmgen_node_tools/PeerBlocks.py +++ b/mmgen_node_tools/PeerBlocks.py @@ -14,7 +14,6 @@ mmgen_node_tools.PeerBlocks: List blocks in flight, disconnect stalling nodes import asyncio from collections import namedtuple -from mmgen.globalvars import g 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 @@ -30,15 +29,15 @@ class Display(PollDisplay): poll_secs = 2 - def __init__(self): + def __init__(self,cfg): - super().__init__() + super().__init__(cfg) global term,term_width if not term: term = get_term() term.init(noecho=True) - term_width = g.columns or get_terminal_size().width + term_width = self.cfg.columns or get_terminal_size().width msg_r(CUR_HOME+ERASE_ALL+CUR_HOME) async def get_info(self,rpc): @@ -69,7 +68,7 @@ class Display(PollDisplay): msg('') term.reset() # readline required for correct operation here; without it, user must re-type first digit - ret = line_input('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) self.enable_display = False # prevent display from updating before process_input() return ret diff --git a/mmgen_node_tools/PollDisplay.py b/mmgen_node_tools/PollDisplay.py index bff4683..84a6023 100755 --- a/mmgen_node_tools/PollDisplay.py +++ b/mmgen_node_tools/PollDisplay.py @@ -22,7 +22,8 @@ class PollDisplay(): input = None poll_secs = 1 - def __init__(self): + def __init__(self,cfg): + self.cfg = cfg self.info_lock = threading.Lock() # self.info accessed by 2 threads self.display_kill_flag = threading.Event() diff --git a/mmgen_node_tools/Ticker.py b/mmgen_node_tools/Ticker.py index 7fe8b1d..e4b147c 100755 --- a/mmgen_node_tools/Ticker.py +++ b/mmgen_node_tools/Ticker.py @@ -28,10 +28,8 @@ import sys,os,time,json,yaml from subprocess import run,PIPE,CalledProcessError from decimal import Decimal from collections import namedtuple -from mmgen.opts import opt -from mmgen.globalvars import g from mmgen.color import * -from mmgen.util import die,fmt_list,msg,msg_r,Msg,vmsg,suf,fmt,stdout_or_pager +from mmgen.util import die,fmt_list,msg,msg_r,suf,fmt homedir = os.getenv('HOME') cachedir = os.path.join(homedir,'.cache','mmgen-node-tools') @@ -173,23 +171,23 @@ def get_src_data(curl_cmd): if cfg.btc_only: fn = os.path.join(cfg.cachedir,'ticker-btc.json') - timeout = 5 if g.test_suite else btc_ratelimit + timeout = 5 if gcfg.test_suite else btc_ratelimit else: fn = os.path.join(cfg.cachedir,'ticker.json') - timeout = 5 if g.test_suite else ratelimit + timeout = 5 if gcfg.test_suite else ratelimit fn_rel = os.path.relpath(fn,start=homedir) if not os.path.exists(fn): open(fn,'w').write('{}') - if opt.cached_data: + if gcfg.cached_data: json_text = open(fn).read() else: elapsed = int(time.time() - os.stat(fn).st_mtime) if elapsed >= timeout: msg_r(f'Fetching data from {api_host}...') - vmsg('') + gcfg._util.vmsg('') try: cp = run(curl_cmd,check=True,stdout=PIPE) except CalledProcessError as e: @@ -212,14 +210,14 @@ def get_src_data(curl_cmd): die(2,'Retrieved data is not valid JSON, exiting') if not data: - if opt.cached_data: + if gcfg.cached_data: die(1,'No cached data! Run command without --cached-data option to retrieve data from remote host') else: die(2,'Remote host returned no data!') elif 'error' in data: die(1,data['error']) - if opt.cached_data: + if gcfg.cached_data: msg(f'Using cached data from ~/{fn_rel}') else: open(fn,'w').write(json_text) @@ -248,7 +246,7 @@ def main(cfg_parm,cfg_in_parm): '--header', 'Accept: application/json', ] + (['--proxy', cfg.proxy] if cfg.proxy else []) + - (['--silent'] if not opt.verbose else []) + + (['--silent'] if not gcfg.verbose else []) + [api_url + ('/btc-bitcoin' if cfg.btc_only else '')] ) @@ -264,27 +262,27 @@ def main(cfg_parm,cfg_in_parm): update_sample_file(cfg_in.cfg_file) update_sample_file(cfg_in.portfolio_file) - if opt.portfolio and not cfg_in.portfolio: + if gcfg.portfolio and not cfg_in.portfolio: die(1,'No portfolio configured!\nTo configure a portfolio, edit the file ~/{}'.format( os.path.relpath(cfg_in.portfolio_file,start=homedir))) curl_cmd = get_curl_cmd() - if opt.print_curl: + if gcfg.print_curl: Msg(curl_cmd + '\n' + ' '.join(curl_cmd)) return parsed_json = [get_src_data(curl_cmd)] if cfg.btc_only else get_src_data(curl_cmd) - if opt.list_ids: + if gcfg.list_ids: from mmgen.ui import do_pager do_pager('\n'.join(e['id'] for e in parsed_json)) return global now - now = 1659465400 if g.test_suite else time.time() # 1659524400 1659445900 + now = 1659465400 if gcfg.test_suite else time.time() # 1659524400 1659445900 - stdout_or_pager( + gcfg._util.stdout_or_pager( '\n'.join(getattr(Ticker,cfg.clsname)(dict(gen_data(parsed_json))).gen_output()) + '\n' ) @@ -366,12 +364,12 @@ def make_cfg(cmd_args,cfg_in): usr_columns ) def get_portfolio_assets(ret=()): - if cfg_in.portfolio and opt.portfolio: + if cfg_in.portfolio and gcfg.portfolio: ret = (parse_asset_id(e,True) for e in cfg_in.portfolio) - return ( 'portfolio', tuple(e for e in ret if (not opt.btc) or e.symbol == 'BTC') ) + return ( 'portfolio', tuple(e for e in ret if (not gcfg.btc) or e.symbol == 'BTC') ) def get_portfolio(): - return {k:Decimal(v) for k,v in cfg_in.portfolio.items() if (not opt.btc) or k == 'btc-bitcoin'} + return {k:Decimal(v) for k,v in cfg_in.portfolio.items() if (not gcfg.btc) or k == 'btc-bitcoin'} def parse_add_precision(s): if not s: @@ -385,8 +383,8 @@ def make_cfg(cmd_args,cfg_in): def create_rows(): rows = ( ('trade_pair',) + query if (query and query.to_asset) else - ('bitcoin',parse_asset_id('btc-bitcoin')) if opt.btc else - get_rows_from_cfg( add_data={'fiat':['usd-us-dollar']} if opt.add_columns else None ) + ('bitcoin',parse_asset_id('btc-bitcoin')) if gcfg.btc else + get_rows_from_cfg( add_data={'fiat':['usd-us-dollar']} if gcfg.add_columns else None ) ) for hdr,data in ( @@ -416,8 +414,8 @@ def make_cfg(cmd_args,cfg_in): asset_data = namedtuple('asset_data',['symbol','id','amount','rate','rate_asset']) asset_tuple = namedtuple('asset_tuple',['symbol','id']) - usr_rows = parse_usr_asset_arg(opt.add_rows) - usr_columns = parse_usr_asset_arg(opt.add_columns) + usr_rows = parse_usr_asset_arg(gcfg.add_rows) + usr_columns = parse_usr_asset_arg(gcfg.add_columns) query = parse_query_arg(cmd_args[0]) if cmd_args else None return cfg_tuple( @@ -425,19 +423,19 @@ def make_cfg(cmd_args,cfg_in): usr_rows = usr_rows, usr_columns = usr_columns, query = query, - adjust = ( lambda x: (100 + x) / 100 if x else 1 )( Decimal(opt.adjust or 0) ), + adjust = ( lambda x: (100 + x) / 100 if x else 1 )( Decimal(gcfg.adjust or 0) ), clsname = 'trading' if query else 'overview', - btc_only = opt.btc, - add_prec = parse_add_precision(opt.add_precision), - cachedir = opt.cachedir or cfg_in.cfg.get('cachedir') or cachedir, - proxy = None if opt.proxy == '' else (opt.proxy or cfg_in.cfg.get('proxy')), - portfolio = get_portfolio() if cfg_in.portfolio and opt.portfolio and not query else None + btc_only = gcfg.btc, + add_prec = parse_add_precision(gcfg.add_precision), + cachedir = gcfg.cachedir or cfg_in.cfg.get('cachedir') or cachedir, + proxy = None if gcfg.proxy == '' else (gcfg.proxy or cfg_in.cfg.get('proxy')), + portfolio = get_portfolio() if cfg_in.portfolio and gcfg.portfolio and not query else None ) def get_cfg_in(): ret = namedtuple('cfg_in_data',['cfg','portfolio','cfg_file','portfolio_file']) cfg_file,portfolio_file = ( - [os.path.join(g.data_dir_root,'node_tools',fn) for fn in (cfg_fn,portfolio_fn)] + [os.path.join(gcfg.data_dir_root,'node_tools',fn) for fn in (cfg_fn,portfolio_fn)] ) cfg_data,portfolio_data = ( [yaml.safe_load(open(fn).read()) if os.path.exists(fn) else None for fn in (cfg_file,portfolio_file)] @@ -466,10 +464,10 @@ class Ticker: def __init__(self,data): - self.comma = ',' if opt.thousands_comma else '' + self.comma = ',' if gcfg.thousands_comma else '' self.col1_wid = max(len('TOTAL'),( - max(len(self.create_label(d['id'])) for d in data.values()) if opt.name_labels else + max(len(self.create_label(d['id'])) for d in data.values()) if gcfg.name_labels else max(len(d['symbol']) for d in data.values()) )) + 1 @@ -482,7 +480,7 @@ class Ticker: def format_last_update_col(self,cross_assets=()): - if opt.elapsed: + if gcfg.elapsed: from mmgen.util2 import format_elapsed_hr fmt_func = format_elapsed_hr else: @@ -627,7 +625,7 @@ class Ticker: amt_fmt = amt_fmt.rstrip('0').rstrip('.') return self.fs_num.format( - lbl = (self.create_label(d['id']) if opt.name_labels else d['symbol']), + lbl = (self.create_label(d['id']) if gcfg.name_labels else d['symbol']), pc1 = fmt_pct(d.get('percent_change_7d')), pc2 = fmt_pct(d.get('percent_change_24h')), upd = d.get('last_updated_fmt'), @@ -670,13 +668,13 @@ class Ticker: [asset.id for asset in self.usr_col_assets] + [a for a,b in ( ( 'btc-bitcoin', not cfg.btc_only ), - ( 'pct7d', opt.percent_change ), - ( 'pct24h', opt.percent_change ), - ( 'update_time', opt.update_time ), + ( 'pct7d', gcfg.percent_change ), + ( 'pct24h', gcfg.percent_change ), + ( 'update_time', gcfg.update_time ), ) if b] ) cols2 = list(cols) - if opt.update_time: + if gcfg.update_time: cols2.pop() cols2.append('amt') @@ -759,7 +757,7 @@ class Ticker: if self.show_adj: self.fs_str += ' {p_adj}' self.hl_wid += self.max_wid + 1 - if opt.update_time: + if gcfg.update_time: self.fs_str += ' {upd}' self.hl_wid += self.upd_w + 2 @@ -772,7 +770,7 @@ class Ticker: if self.show_adj else '' ) return self.fs_str.format( - lbl = (self.create_label(id) if opt.name_labels else d['symbol']), + lbl = (self.create_label(id) if gcfg.name_labels else d['symbol']), p_spot = green(p_spot) if id in self.hl_ids else p_spot, p_adj = yellow(p_adj) if id in self.hl_ids else p_adj, upd = d.get('last_updated_fmt'), diff --git a/mmgen_node_tools/data/version b/mmgen_node_tools/data/version index 1bc37c8..4348263 100644 --- a/mmgen_node_tools/data/version +++ b/mmgen_node_tools/data/version @@ -1 +1 @@ -3.1.dev14 +3.1.dev15 diff --git a/mmgen_node_tools/main_addrbal.py b/mmgen_node_tools/main_addrbal.py index b0ab4f8..9f2e11e 100755 --- a/mmgen_node_tools/main_addrbal.py +++ b/mmgen_node_tools/main_addrbal.py @@ -71,7 +71,7 @@ def do_output_tabular(proto,addr_data,blk_hdrs): fs = ( ' {n:>%s} {a} {u} {b:>%s} {t:19} {B:>%s} {T:19} {A}' % (col1w,max(5,fb_w),max(4,lb_w)) - if opt.first_block else + if cfg.first_block else ' {n:>%s} {a} {u} {B:>%s} {T:19} {A}' % (col1w,max(4,lb_w)) ) Msg('\n' + fs.format( @@ -109,20 +109,19 @@ def do_output_tabular(proto,addr_data,blk_hdrs): async def main(req_addrs): - from mmgen.protocol import init_proto_from_opts - proto = init_proto_from_opts(need_amt=True) + proto = cfg._proto from mmgen.addr import CoinAddr addrs = [CoinAddr(proto,addr) for addr in req_addrs] from mmgen.rpc import rpc_init - rpc = await rpc_init(proto) + rpc = await rpc_init( cfg, proto ) height = await rpc.call('getblockcount') Msg(f'{proto.coin} {proto.network.upper()} [height {height}]') from mmgen.proto.btc.misc import scantxoutset - res = await scantxoutset( rpc, [f'addr({addr})' for addr in addrs] ) + res = await scantxoutset( cfg, rpc, [f'addr({addr})' for addr in addrs] ) if not res['success']: die(1,'UTXO scanning failed or was interrupted') @@ -155,16 +154,16 @@ async def main(req_addrs): 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]) - (do_output_tabular if opt.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)) ) -cmd_args = opts.init(opts_data,init_opts={'rpc_backend':'aiohttp'}) +cfg = opts.init(opts_data,init_opts={'rpc_backend':'aiohttp'}) -if len(cmd_args) < 1: +if len(cfg._args) < 1: die(1,'This command requires at least one coin address argument') from mmgen.obj import CoinTxID,Int try: - async_run(main(cmd_args)) + async_run(main(cfg._args)) except KeyboardInterrupt: sys.stderr.write('\n') diff --git a/mmgen_node_tools/main_blocks_info.py b/mmgen_node_tools/main_blocks_info.py index eb12a5c..38914c5 100755 --- a/mmgen_node_tools/main_blocks_info.py +++ b/mmgen_node_tools/main_blocks_info.py @@ -20,7 +20,9 @@ mmnode-blocks-info: Display information about a block or range of blocks """ -from mmgen.common import * +import mmgen.opts as opts +from mmgen.globalvars import gc +from mmgen.util import async_run,fmt_list from .BlocksInfo import BlocksInfo,JSONBlocksInfo opts_data = { @@ -146,29 +148,26 @@ EXAMPLES: This program requires a txindex-enabled daemon for correct operation. """ }, 'code': { - 'notes': lambda proto,s: s.format( + 'notes': lambda cfg,proto,s: s.format( I = proto.diff_adjust_interval, F = fmt_list(BlocksInfo.fields,fmt='bare'), S = fmt_list(BlocksInfo.all_stats,fmt='bare'), - p = g.prog_name, + p = gc.prog_name, ) } } -cmd_args = opts.init(opts_data) +cfg = opts.init(opts_data) async def main(): - from mmgen.protocol import init_proto_from_opts from mmgen.rpc import rpc_init - proto = init_proto_from_opts(need_amt=True) + cls = JSONBlocksInfo if cfg.json else BlocksInfo - cls = JSONBlocksInfo if opt.json else BlocksInfo + m = cls( cfg, cfg._args, await rpc_init(cfg,cfg._proto) ) - m = cls( cmd_args, opt, await rpc_init(proto) ) - - if m.fnames and not opt.no_header: + if m.fnames and not cfg.no_header: m.print_header() await m.process_blocks() diff --git a/mmgen_node_tools/main_feeview.py b/mmgen_node_tools/main_feeview.py index ce1fbdb..f5212e3 100755 --- a/mmgen_node_tools/main_feeview.py +++ b/mmgen_node_tools/main_feeview.py @@ -39,7 +39,7 @@ fee_brackets = [ 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 2100000000000000, ] -opts.init({ +cfg = opts.init({ 'sets': [ ('detail',True,'ranges',True), ('detail',True,'show_mb_col',True), @@ -78,17 +78,17 @@ factors. } }) -if opt.ignore_below: - if opt.show_empty: +if cfg.ignore_below: + if cfg.show_empty: die(1,'Conflicting options: --ignore-below, --show-empty') - ignore_below = parse_bytespec(opt.ignore_below) + ignore_below = parse_bytespec(cfg.ignore_below) precision = ( - check_int_between(opt.precision,min_prec,max_prec,'--precision arg') - if opt.precision else dfl_prec ) + check_int_between(cfg.precision,min_prec,max_prec,'--precision arg') + if cfg.precision else dfl_prec ) from mmgen.term import get_terminal_size -width = g.columns or get_terminal_size().width +width = cfg.columns or get_terminal_size().width class fee_bracket: def __init__(self,top,bottom): @@ -103,6 +103,7 @@ def log(data,fn): from mmgen.rpc import json_encoder from mmgen.fileutil import write_data_to_file write_data_to_file( + cfg = cfg, outfile = fn, data = json.dumps(data,cls=json_encoder,sort_keys=True,indent=4), desc = 'mempool', @@ -130,9 +131,9 @@ def create_data(coin_amt,mempool): # calculate cumulative byte totals, filter rows: tBytes = 0 for i in out: - if not (i.tx_bytes or opt.show_empty): + if not (i.tx_bytes or cfg.show_empty): i.skip = True - if opt.ignore_below and i.tx_bytes < ignore_below: + if cfg.ignore_below and i.tx_bytes < ignore_below: i.skip = True i.tx_bytes_cum = tBytes tBytes += i.tx_bytes @@ -150,15 +151,15 @@ def gen_header(host,mempool,blockcount): TX count: {len(mempool)} """)).strip() - if opt.show_empty: + if cfg.show_empty: yield('Displaying all fee brackets') - elif opt.ignore_below: + elif cfg.ignore_below: yield('Ignoring fee brackets with less than {:,} bytes ({})'.format( ignore_below, int2bytespec(ignore_below,'MB','0.6',strip=True,add_space=True), )) - if opt.include_current: + if cfg.include_current: yield('Including transactions in current fee bracket in Total MB amounts') def fmt_mb(n): @@ -168,11 +169,11 @@ 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 opt.ranges else len(f'{top_max}'),6) - col2_w = len(fmt_mb(tx_bytes_max)) if opt.show_mb_col else 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 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) - if opt.show_mb_col: + if cfg.show_mb_col: fs = '{a:<%i} {b:>%i} {c:>%i} {d}' % (col1_w,col2_w,col3_w) else: fs = '{a:<%i} {c:>%i} {d}' % (col1_w,col3_w) @@ -182,9 +183,9 @@ def gen_body(data): for i in data: if not i.skip: - cum_bytes = i.tx_bytes_cum + i.tx_bytes if opt.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( - a = '{}-{}'.format(i.bottom,i.top) if opt.ranges else i.top, + a = '{}-{}'.format(i.bottom,i.top) if cfg.ranges else i.top, b = fmt_mb(i.tx_bytes), c = fmt_mb(cum_bytes), d = '-' * int(col4_w * ( i.tx_bytes / tx_bytes_max )) )) @@ -197,20 +198,19 @@ def gen_body(data): async def main(): - from mmgen.protocol import init_proto_from_opts global proto - proto = init_proto_from_opts(need_amt=True) + proto = cfg._proto from mmgen.rpc import rpc_init - c = await rpc_init(proto) + c = await rpc_init( cfg, proto ) mempool = await c.call('getrawmempool',True) - if opt.log: + if cfg.log: log(mempool,'mempool.json') data = create_data(proto.coin_amt,mempool) - stdout_or_pager( + cfg._util.stdout_or_pager( '\n'.join(gen_header( c.host, mempool, diff --git a/mmgen_node_tools/main_halving_calculator.py b/mmgen_node_tools/main_halving_calculator.py index 5cbf2b8..e92d161 100755 --- a/mmgen_node_tools/main_halving_calculator.py +++ b/mmgen_node_tools/main_halving_calculator.py @@ -26,7 +26,7 @@ from mmgen.common import * bdr_proj = 9.95 -opts.init({ +cfg = opts.init({ 'sets': [('mined',True,'list',True)], 'text': { 'desc': 'Estimate date(s) of future block subsidy halving(s)', @@ -43,8 +43,8 @@ opts.init({ """ } }) -if opt.bdr_proj: - bdr_proj = float(opt.bdr_proj) +if cfg.bdr_proj: + bdr_proj = float(cfg.bdr_proj) def date(t): return '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(*time.gmtime(t)[:6]) @@ -61,16 +61,15 @@ def time_diff_warning(t_diff): async def main(): - from mmgen.protocol import init_proto_from_opts - proto = init_proto_from_opts(need_amt=True) + proto = cfg._proto from mmgen.rpc import rpc_init - c = await rpc_init(proto) + c = await rpc_init( cfg, proto ) tip = await c.call('getblockcount') assert tip > 1, 'block tip must be > 1' remaining = proto.halving_interval - tip % proto.halving_interval - sample_size = int(opt.sample_size) if opt.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,))) @@ -134,7 +133,7 @@ async def main(): fs = ( ' {a:<7} {b:>8} {c:19}{d:2} {e:10} {f}', ' {a:<7} {b:>8} {c:19}{d:2} {e:10} {f:17} {g:17} {h}' - )[bool(opt.mined)] + )[bool(cfg.mined)] print( f'Historical/Estimated/Projected Halvings ({proto.coin}):\n\n' @@ -174,7 +173,7 @@ async def main(): ) for n,sub,blk,mined,total_mined,bdr,t in gen_data()) ) - if opt.list: + if cfg.list: await print_halvings() else: print_current_stats() diff --git a/mmgen_node_tools/main_netrate.py b/mmgen_node_tools/main_netrate.py index fd86983..78c9823 100755 --- a/mmgen_node_tools/main_netrate.py +++ b/mmgen_node_tools/main_netrate.py @@ -34,17 +34,14 @@ opts_data = { } } -cmd_args = opts.init(opts_data) +cfg = opts.init(opts_data) ERASE_LINE,CUR_UP = '\033[K','\033[1A' async def main(): - from mmgen.protocol import init_proto_from_opts - proto = init_proto_from_opts() - from mmgen.rpc import rpc_init - c = await rpc_init(proto) + c = await rpc_init( cfg, cfg._proto ) async def get_data(): d = await c.call('getnettotals') diff --git a/mmgen_node_tools/main_peerblocks.py b/mmgen_node_tools/main_peerblocks.py index 9e6a0ec..af723c9 100755 --- a/mmgen_node_tools/main_peerblocks.py +++ b/mmgen_node_tools/main_peerblocks.py @@ -20,7 +20,7 @@ mmnode-peerblocks: List blocks in flight, disconnect stalling nodes """ -from mmgen.opts import init +import mmgen.opts as opts from mmgen.util import async_run opts_data = { @@ -36,17 +36,14 @@ opts_data = { async def main(): - init(opts_data) - - from mmgen.protocol import init_proto_from_opts - proto = init_proto_from_opts() + cfg = opts.init(opts_data) from mmgen.rpc import rpc_init - rpc = await rpc_init(proto) + rpc = await rpc_init( cfg, cfg._proto ) from .PeerBlocks import BlocksDisplay,PeersDisplay - blocks = BlocksDisplay() - peers = PeersDisplay() + blocks = BlocksDisplay(cfg) + peers = PeersDisplay(cfg) while True: await blocks.run(rpc) diff --git a/mmgen_node_tools/main_ticker.py b/mmgen_node_tools/main_ticker.py index a25e884..da96bb8 100755 --- a/mmgen_node_tools/main_ticker.py +++ b/mmgen_node_tools/main_ticker.py @@ -197,12 +197,15 @@ To add a portfolio, edit the file } } -cmd_args = opts.init(opts_data,do_post_init=True) +gcfg = opts.init(opts_data,do_post_init=True) + +import mmgen_node_tools.Ticker as Ticker +Ticker.gcfg = gcfg cfg_in = get_cfg_in() -cfg = make_cfg(cmd_args,cfg_in) +cfg = make_cfg(gcfg._args,cfg_in) -opts.post_init() +opts.post_init(gcfg) main(cfg,cfg_in) diff --git a/mmgen_node_tools/main_txfind.py b/mmgen_node_tools/main_txfind.py index d0a04e2..4c0bcc2 100755 --- a/mmgen_node_tools/main_txfind.py +++ b/mmgen_node_tools/main_txfind.py @@ -58,14 +58,11 @@ async def main(txid): if len(txid) != 64 or not is_hex_str(txid): die(2,f'{txid}: invalid transaction ID') - if opt.verbose: + if cfg.verbose: msg(f'TxID: {txid}') - from mmgen.protocol import init_proto_from_opts - proto = init_proto_from_opts() - from mmgen.rpc import rpc_init - c = await rpc_init(proto) + c = await rpc_init(cfg._proto) exitval = 0 try: @@ -85,11 +82,11 @@ async def main(txid): return exitval -cmd_args = opts.init(opts_data) +cfg = opts.init(opts_data) -msgs = msg_data['quiet' if opt.quiet else 'normal'] +msgs = msg_data['quiet' if cfg.quiet else 'normal'] -if len(cmd_args) != 1: +if len(cfg._args) != 1: die(1,'One transaction ID must be specified') -sys.exit(async_run(main(cmd_args[0]))) +sys.exit(async_run(main(cfg._args[0]))) diff --git a/setup.cfg b/setup.cfg index 65b9639..e669735 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,7 +23,7 @@ python_requires = >=3.7 include_package_data = True install_requires = - mmgen>=13.3.dev20 + mmgen>=13.3.dev42 packages = mmgen_node_tools diff --git a/test/test_py_d/ts_main.py b/test/test_py_d/ts_main.py index 171ffc5..162e3fb 100755 --- a/test/test_py_d/ts_main.py +++ b/test/test_py_d/ts_main.py @@ -45,7 +45,7 @@ class TestSuiteMain(TestSuiteBase): f'mmnode-peerblocks', args, pexpect_spawn = pexpect_spawn ) - if opt.exact_output: # disable echoing of input + if cfg.exact_output: # disable echoing of input t.p.logfile = None t.p.logfile_read = sys.stdout if expect_list: diff --git a/test/test_py_d/ts_misc.py b/test/test_py_d/ts_misc.py index cc4c22d..c4536d6 100755 --- a/test/test_py_d/ts_misc.py +++ b/test/test_py_d/ts_misc.py @@ -97,7 +97,7 @@ class TestSuiteScripts(TestSuiteBase): @property def nt_datadir(self): - return os.path.join( g.data_dir_root, 'node_tools' ) + return os.path.join( cfg.data_dir_root, 'node_tools' ) def ticker_setup(self): self.spawn('',msg_only=True) @@ -120,7 +120,7 @@ class TestSuiteScripts(TestSuiteBase): def ticker2(self): t = self.ticker(cached=False) - if not opt.skipping_deps: + if not cfg.skipping_deps: t.expect('Creating') t.expect('Creating') t.expect('proxy host could not be resolved') diff --git a/test/test_py_d/ts_regtest.py b/test/test_py_d/ts_regtest.py index fd19099..e208373 100755 --- a/test/test_py_d/ts_regtest.py +++ b/test/test_py_d/ts_regtest.py @@ -13,8 +13,6 @@ test.test_py_d.ts_regtest: Regtest tests for the test.py test suite """ import os -from mmgen.globalvars import g -from mmgen.opts import opt from mmgen.util import die,gmsg from mmgen.protocol import init_proto from mmgen.proto.btc.regtest import MMGenRegtest @@ -28,7 +26,7 @@ args2 = ['--bob','--rpc-backend=http'] def gen_addrs(proto,network,keys): from mmgen.tool.api import tool_api - tool = tool_api() + tool = tool_api(cfg) tool.init_coin(proto.coin,'regtest') tool.addrtype = proto.mmtypes[-1] return [tool.privhex2addr('{:064x}'.format(key)) for key in keys] @@ -105,9 +103,9 @@ class TestSuiteRegtest(TestSuiteBase): return if self.proto.testnet: die(2,'--testnet and --regtest options incompatible with regtest test suite') - self.proto = init_proto(self.proto.coin,network='regtest',need_amt=True) + self.proto = init_proto( cfg, self.proto.coin, network='regtest', need_amt=True ) self.addrs = gen_addrs(self.proto,'regtest',[1,2,3,4,5]) - self.regtest = MMGenRegtest(self.proto.coin) + self.regtest = MMGenRegtest(cfg,self.proto.coin) def setup(self): stop_test_daemons(self.proto.network_id,force=True,remove_datadir=True) @@ -128,7 +126,7 @@ class TestSuiteRegtest(TestSuiteBase): return self.halving_calculator(['--help'],['USAGE:']) def halving_calculator2(self): - return self.halving_calculator([],['Current block: 393',f'Current block subsidy: 12.5 {g.coin}']) + return self.halving_calculator([],['Current block: 393',f'Current block subsidy: 12.5 {cfg.coin}']) def halving_calculator3(self): return self.halving_calculator(['--list'],['33 4950','0']) @@ -158,7 +156,7 @@ class TestSuiteRegtest(TestSuiteBase): return self.addrbal( args2 + [self.addrs[0]], [ - f'Balance: 0.357 {g.coin}', + f'Balance: 0.357 {cfg.coin}', '2 unspent outputs in 2 blocks', '394','0.123', '395','0.234' @@ -246,7 +244,7 @@ class TestSuiteRegtest(TestSuiteBase): ]) def blocks_info4(self): - n1,i1,o1,n2,i2,o2 = (2,1,3,6,3,9) if g.coin == 'BCH' else (2,1,4,6,3,12) + n1,i1,o1,n2,i2,o2 = (2,1,3,6,3,9) if cfg.coin == 'BCH' else (2,1,4,6,3,12) return self.blocks_info( args1 + ['--miner-info','--fields=all','--stats=all','+3'], [ 'Averages', f'nTx: {n1}', @@ -267,7 +265,7 @@ class TestSuiteRegtest(TestSuiteBase): from mmgen.tool.api import tool_api from collections import namedtuple - t = tool_api() + t = tool_api(cfg) t.init_coin(self.proto.coin,self.proto.network) t.addrtype = 'compressed' if self.proto.coin == 'BCH' else 'bech32' wp = namedtuple('wifaddrpair',['wif','addr']) @@ -384,7 +382,7 @@ class TestSuiteRegtest(TestSuiteBase): return self._feeview([]) def stop(self): - if opt.no_daemon_stop: + if cfg.no_daemon_stop: self.spawn('',msg_only=True) msg_r('(leaving daemon running by user request)') return 'ok' diff --git a/test/unit_tests_d/ut_BlocksInfo.py b/test/unit_tests_d/ut_BlocksInfo.py index ab09882..e65e314 100755 --- a/test/unit_tests_d/ut_BlocksInfo.py +++ b/test/unit_tests_d/ut_BlocksInfo.py @@ -7,6 +7,8 @@ from mmgen.common import * from mmgen.exception import * from mmgen_node_tools.BlocksInfo import BlocksInfo +from ..include.common import cfg,vmsg + tip = 50000 range_vecs = ( # First Last FromTip nBlocks Step First Last BlockList @@ -70,12 +72,13 @@ class dummyRPC: class coin_amt: satoshi = 0.00000001 -class dummyOpt: +class dummyCfg: fields = None stats = None miner_info = None header_info = None full_stats = None + coin = 'BTC' class unit_tests: @@ -91,7 +94,7 @@ class unit_tests: def parse_rangespec(self,name,ut): - b = BlocksInfo(0,dummyOpt(),dummyRPC()) + b = BlocksInfo(dummyCfg(),None,dummyRPC()) def test(spec,chk,foo): ret = b.parse_rangespec(spec) @@ -108,8 +111,8 @@ class unit_tests: def test(spec,foo,chk): b = BlocksInfo( + dummyCfg(), spec if type(spec) == tuple else [spec], - dummyOpt(), dummyRPC() ) ret = (b.first,b.last,b.block_list) vmsg('{:13} => {}'.format(