diff --git a/mmgen_node_tools/PeerBlocks.py b/mmgen_node_tools/PeerBlocks.py new file mode 100755 index 0000000..a6027ca --- /dev/null +++ b/mmgen_node_tools/PeerBlocks.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen + +""" +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 +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') +term = None + +class Display(PollDisplay): + + poll_secs = 2 + + def __init__(self): + super().__init__() + + global term,term_width + if not term: + term = get_term() + term.init(noecho=True) + term_width = g.columns or get_terminal_size()[0] + msg_r(CUR_HOME+ERASE_ALL+CUR_HOME) + + async def get_info(self,rpc): + return await rpc.call('getpeerinfo') + + def display(self,count): + msg_r( + CUR_HOME + + (ERASE_ALL if count == 1 else '') + + 'CONNECTED PEERS ({a}) {b} - poll {c}'.format( + a = len(self.info), + b = self.desc, + c = count ).ljust(term_width)[:term_width] + + '\n' + + ('\n'.join(self.gen_display()) + '\n' if self.info else '') + + ERASE_ALL + + f"Type a peer number to disconnect, 'q' to quit, or any other key for {self.other_desc} display:" + + '\b' ) + + async def disconnect_node(self,rpc,addr): + return await rpc.call('disconnectnode',addr) + + def get_input(self): + s = get_char(immed_chars='q0123456789',prehold_protect=False,num_chars=1) + if not is_int(s): + return s + with self.info_lock: + msg('') + term.reset() + ret = line_input('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 + + async def process_input(self,rpc): + + ids = tuple(str(i['id']) for i in self.info) + ret = False + msg_r(CUR_HIDE) + + if self.input in ids: + from mmgen.exception import RPCFailure + addr = self.info[ids.index(self.input)]['addr'] + try: + await self.disconnect_node(rpc,addr) + except RPCFailure: + msg_r(f'Unable to disconnect peer {self.input} ({addr})') + else: + msg_r(f'Disconnecting peer {self.input} ({addr})') + await asyncio.sleep(1) + elif self.input and is_int(self.input[0]): + msg_r(f'{self.input}: invalid peer number ') + await asyncio.sleep(0.5) + else: + ret = True + + msg_r(CUR_SHOW) + return ret + +class BlocksDisplay(Display): + + desc = 'Blocks in Flight' + other_desc = 'address' + + def gen_display(self): + + pd = namedtuple('peer_data',['id','blks_data','blks_width']) + bd = namedtuple('block_datum',['num','disp']) + + def gen_block_data(): + global min_height + min_height = None + for d in self.info: + if d.get('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] + blocks_disp = line.split() + yield pd( + d['id'], + [bd(blocks[i],blocks_disp[i]) for i in range(len(blocks_disp))], + len(line) ) + else: + yield pd(d['id'],[],0) + + def gen_line(peer_data): + for blk in peer_data.blks_data: + yield (RED if blk.num == min_height else COLORS[blk.num % 10]) + blk.disp + RESET + + id_width = max(2, max(len(str(i['id'])) for i in self.info)) + blks_field_width = term_width - 2 - id_width + fs = '{:>%s}: {}' % id_width + + # we must iterate through all data to get 'min_height' before calling gen_line(): + for peer_data in tuple(gen_block_data()): + yield fs.format( + peer_data.id, + ' '.join(gen_line(peer_data)) + ' ' * (blks_field_width - peer_data.blks_width) ) + +class PeersDisplay(Display): + + desc = 'Address Menu' + other_desc = 'blocks' + + def gen_display(self): + id_width = max(2, max(len(str(i['id'])) for i in self.info)) + addr_width = max(len(str(i['addr'])) for i in self.info) + for d in self.info: + yield '{a:>{A}}: {b:{B}} {c}'.format( + a = d['id'], + A = id_width, + b = d['addr'], + B = addr_width, + c = d['subver'] + ).ljust(term_width)[:term_width] diff --git a/mmgen_node_tools/PollDisplay.py b/mmgen_node_tools/PollDisplay.py new file mode 100755 index 0000000..06b7d7f --- /dev/null +++ b/mmgen_node_tools/PollDisplay.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen + +""" +mmgen_node_tools.PollDisplay: update and display RPC data; get input from user +""" + +import sys,threading +from mmgen.util import msg +from mmgen.term import get_char + +class PollDisplay(): + + info = None + input = None + poll_secs = 1 + + def __init__(self): + self.info_lock = threading.Lock() # self.info accessed by 2 threads + self.display_kill_flag = threading.Event() + + def get_input(self): + return get_char(immed_chars='q',prehold_protect=False,num_chars=1) + + async def process_input(self,rpc): + return True + + async def run(self,rpc): + + async def do_display(): + with self.info_lock: + self.info = None + self.input = None + self.enable_display = True + count = 1 + while True: + with self.info_lock: + if self.enable_display: + self.info = await self.get_info(rpc) + self.display(count) + if self.display_kill_flag.wait(self.poll_secs): + self.display_kill_flag.clear() + return + count += 1 + + async def process_input(): + if self.input == None: + sys.exit(1) + elif self.input == 'q': + msg('') + sys.exit(0) + elif self.info: + if await self.process_input(rpc): + return True + else: + return True + + def get_input(): + self.input = self.get_input() + self.display_kill_flag.set() + + while True: + threading.Thread(target=get_input,daemon=True).start() + await do_display() + if await process_input(): + break diff --git a/mmgen_node_tools/data/version b/mmgen_node_tools/data/version index 2d22ff0..1ebddf5 100644 --- a/mmgen_node_tools/data/version +++ b/mmgen_node_tools/data/version @@ -1 +1 @@ -3.1.dev8 +3.1.dev9 diff --git a/mmgen_node_tools/main_peerblocks.py b/mmgen_node_tools/main_peerblocks.py index b775b29..9e6a0ec 100755 --- a/mmgen_node_tools/main_peerblocks.py +++ b/mmgen_node_tools/main_peerblocks.py @@ -20,9 +20,8 @@ mmnode-peerblocks: List blocks in flight, disconnect stalling nodes """ -import asyncio -from collections import namedtuple -from mmgen.common import * +from mmgen.opts import init +from mmgen.util import async_run opts_data = { 'text': { @@ -35,120 +34,9 @@ opts_data = { } } -def format_peer_info(peerinfo): - - pd = namedtuple('peer_data',['id','blocks_data','screen_width']) - - def gen_peers(peerinfo): - global min_height - min_height = None - for d in peerinfo: - if 'inflight' in d and d['inflight']: - blocks = d['inflight'] - if not min_height or min_height > blocks[0]: - min_height = blocks[0] - line = ' '.join(map(str,blocks))[:term_width - 2 - id_width] - blocks_disp = line.split() - yield pd( - d['id'], - [(blocks[i],blocks_disp[i]) for i in range(len(blocks_disp))], - len(line) ) - else: - yield pd( d['id'], [], 0 ) - - def gen_line(peer): - if peer.blocks_data: - if peer.blocks_data[0][0] == min_height: - yield RED + peer.blocks_data[0][1] + RESET - peer.blocks_data.pop(0) - for blk,blk_disp in peer.blocks_data: - yield COLORS[blk % 10] + blk_disp + RESET - - id_width = max(2,max(len(str(i['id'])) for i in peerinfo)) - - for peer in tuple(gen_peers(peerinfo)): - line = '{:>{iw}}: {}'.format( - peer.id, - ' '.join(gen_line(peer)), - iw = id_width ) - yield line + ' ' * (term_width - 2 - id_width - peer.screen_width) - -def test_format(): - import json - info = json.loads(open('test_data/peerinfo.json').read()) - print('\n'.join(format_peer_info(info)) + '\n') - sys.exit(0) - -async def inflight_display(rpc): - - count = 1 - while True: - info = await rpc.call('getpeerinfo') - msg_r( - CUR_HOME - + f'ACTIVE PEERS ({len(info)}) Blocks in Flight - poll {count} \n' - + ('\n'.join(format_peer_info(info)) + '\n' if info else '') - + ERASE_ALL + 'Hit ENTER for disconnect menu: ' ) - await asyncio.sleep(2) - count += 1 - -async def do_inflight(rpc): - task = asyncio.ensure_future(inflight_display(rpc)) # Python 3.7+: create_task() - from select import select - - while True: - key = select([sys.stdin], [], [], 0.1)[0] - if key: - sys.stdin.read(1) - task.cancel() - break - await asyncio.sleep(0.1) - - try: - await task - except asyncio.CancelledError: - pass - -async def do_disconnect_menu(rpc): - - while True: - peerinfo = await rpc.call('getpeerinfo') - ids = [str(d['id']) for d in peerinfo] - - msg(f'{CUR_HOME}ACTIVE PEERS ({len(peerinfo)}) Disconnect Menu' + ' '*16) - - def gen_peerinfo(): - for d in peerinfo: - line = f"{d['id']:>{id_width}}: {d['addr']:30} {d['subver']}" - yield line + ' ' * (term_width - len(line)) - - if peerinfo: - id_width = max(2,max(len(str(i['id'])) for i in peerinfo)) - msg('\n'.join(gen_peerinfo())) - - msg_r(ERASE_ALL) - reply = input("Type peer number to disconnect, ENTER to quit menu, 'u' to update peer list: ") - - if reply == '': - return - elif reply == 'u': - msg(f'Updating peer list') - await asyncio.sleep(0.5) - elif reply in ids: - addr = peerinfo[ids.index(reply)]['addr'] - msg(f'Disconnecting peer {reply} ({addr})') - try: - await rpc.call('disconnectnode',addr) - except RPCFailure: - msg(f'Unable to disconnect peer {addr}') - await asyncio.sleep(1.5) - else: - msg(f'{reply!r}: invalid peer number') - await asyncio.sleep(0.5) - async def main(): - msg_r(CUR_HOME+ERASE_ALL) + init(opts_data) from mmgen.protocol import init_proto_from_opts proto = init_proto_from_opts() @@ -156,23 +44,12 @@ async def main(): from mmgen.rpc import rpc_init rpc = await rpc_init(proto) + from .PeerBlocks import BlocksDisplay,PeersDisplay + blocks = BlocksDisplay() + peers = PeersDisplay() + while True: - await do_inflight(rpc) - await do_disconnect_menu(rpc) + await blocks.run(rpc) + await peers.run(rpc) -opts.init(opts_data) - -from mmgen.term import get_terminal_size -term_width = get_terminal_size()[0] - -RED,RESET = ('\033[31m','\033[0m') -COLORS = ['\033[38;5;%s;1m' % c for c in (247,248,249,250,251,252,253,254,255,231)] -ERASE_ALL,ERASE_LINE,CUR_HOME,CUR_HIDE,CUR_SHOW = ( - '\033[J','\033[K','\033[H','\033[?25l','\033[?25h') - -try: - async_run(main()) -except: - from subprocess import run - run(['stty','sane']) - msg('') +async_run(main()) diff --git a/setup.cfg b/setup.cfg index 327cad7..208e03b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,7 +23,7 @@ python_requires = >=3.7 include_package_data = True install_requires = - mmgen>=13.3.dev8 + mmgen>=13.3.dev9 packages = mmgen_node_tools diff --git a/test/init.sh b/test/init.sh index 0979c76..a8d03a9 100755 --- a/test/init.sh +++ b/test/init.sh @@ -59,7 +59,8 @@ create_dir_links() { create_test_links() { sources=' test/include - test/overlay + test/overlay/__init__.py + test/overlay/fakemods/mmgen test/__init__.py test/test.py test/unit_tests.py diff --git a/test/overlay/fakemods/mmgen_node_tools/PeerBlocks.py b/test/overlay/fakemods/mmgen_node_tools/PeerBlocks.py new file mode 100644 index 0000000..0170a2f --- /dev/null +++ b/test/overlay/fakemods/mmgen_node_tools/PeerBlocks.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen + +""" +fakemods.mmgen_node_tools.PeerBlocks: List blocks in flight, disconnect stalling nodes - test data +""" + +from .PeerBlocks_orig import * + +class fake_data: + + gp_counter = 0 + dn_counter = 0 + poll_secs = 0.5 + + addresses = """ + 0 3tokm3se4omuhhqgaxiam3yhl474ekbg5xb45kydfno57k7ooapitogv.onion:8333 /Satoshi:24.0.0/ + 1 2rysrq5f2ec4zpnsohyb6mc6l6unosjwaydjefttt34ouogdpqtlo7a5.onion:8333 /Satoshi:0.21.1/ + 2 5bkcnkrihwowji7zwko7ddtpcetz6572zbwdh6aguyt2yz3wgvzqa3ne.onion:8333 /Satoshi:23.0.0/ + 3 ukzy7yvako4z6tvtocsm33yvdxwyx567ioqwfezzewlw2syawzkgrw64.onion:8333 /Satoshi:22.0.0/ + 4 b3r3hhxiauujwj7afmji63forvnd7uhq7ov5x2n7w7hvrhutoq3lhul7.onion:8333 /Satoshi:24.0.0/ + 5 ksownpb4zk4vuyfiowgyvz3kzc2djeiurnnh7pyal3if54n5wzup3afm.onion:8333 /Satoshi:22.0.0/ + 6 xh6vhun75w5y2s2xze2n4rarnduqvwowwthhyiaefly3df2t4guwvjrl.onion:8333 /Satoshi:22.0.0/ + 7 raqbaqcsoldmk7sn6fgoh5bicrlzjdoexz5b2z7jemxb2u6z62vpxto2.onion:8333 /Satoshi:23.0.0/ + 8 5gu3m7jr4tog5tuyisek2fxl5erjgasrxzarnii6cpemmvqhate36hrg.onion:8333 /Satoshi:25.1.0(Aldebaran 3.2.1)/ + 9 ayiyxqgckls4fmzrbbh35ppquhstzhm453xezvzmuoglhnibrxu5ebos.onion:8333 /Satoshi:22.0.0/ + 10 3zmyku3xqrb4mebi2r6l65l5ovmf5yjou2zeywgz5g2ehiqbclppwy6t.onion:8333 /Satoshi:23.0.0/ + 11 ljyfsi4wponyw52o5y75bn6oxktw7kiaes3vdtzf26scapei2ed6yw4m.onion:8333 /Satoshi:0.21.0/ + 12 n5hsupofuhis2xfx7neahntqjl2l3jjp7ait6jsegrp4utj7573qgqsp.onion:8333 /Satoshi:22.0.0/ + 13 klw3dgcuzr4etnkgw5ysnukfl46urhnqrlvjt53v544p32o7acakyps4.onion:8333 /Satoshi:23.0.0/ + 14 icmdqoko4nnqp4aiamiqihbvqlumqrmidyb7n54jdif2uki3qkprwsvd.onion:8333 /Satoshi:24.1.0/ + """ + + # connected peers for each iteration + iterations = """ + 01 0 1 2 3 4 5 6 7 8 + 02 0 1 2 3 4 5 6 7 + 03 0 1 2 3 4 5 6 7 8 + 04 0 2 3 4 5 6 7 8 9 + 05 0 2 3 4 5 6 7 8 9 + 06 0 2 3 4 5 6 7 8 9 10 + 07 0 2 3 4 5 6 7 8 9 10 + 08 0 2 3 4 5 6 7 8 9 10 + 09 0 2 3 4 5 6 7 8 9 10 + 10 0 2 3 4 5 6 7 8 9 10 + 11 2 3 4 5 6 7 8 9 10 + 12 2 3 4 5 6 7 8 9 10 + 13 2 3 4 5 6 7 8 9 10 + 14 2 3 4 5 6 7 8 9 10 + 15 2 3 4 5 6 7 8 9 10 12 + 16 2 3 4 5 6 7 8 9 10 12 + 17 2 3 4 5 6 7 8 9 10 12 + 18 2 3 4 5 6 7 8 9 10 12 + 19 2 3 5 6 7 8 9 10 12 + 20 2 3 5 6 7 8 9 10 12 + 21 2 3 5 6 7 8 9 10 12 + 22 2 3 5 6 7 8 9 10 12 + """ + + # blocks in flight for each iteration for each peer + blocks = { + '0': """ + 01 6917 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 + 02 6917 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 + 03 6917 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 + 04 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 + 05 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 + 06 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 + 07 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 + 08 6918 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 + 09 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 7183 + 10 6920 6937 6939 6942 6944 6946 6947 6950 6951 6953 6971 6976 6985 7083 6913 7183 + """, + '1': """ + 01 6906 6907 6908 6909 6910 6911 6913 6915 6919 6940 6948 6982 6988 7000 7023 7062 + 02 6906 6907 6908 6909 6910 6911 6913 6915 6919 6940 6948 6982 6988 7000 7023 7062 + 03 6908 6909 6910 6911 6913 6915 6919 6940 6948 6982 6988 7000 7023 7062 7088 7107 + """, + '2': """ + 01 6990 6994 6996 6997 6999 7017 7018 7019 7020 7021 7025 7059 7060 7061 7082 7084 + 02 6990 6994 6996 6997 6999 7017 7018 7019 7020 7021 7025 7059 7060 7061 7082 7084 + 03 6997 6999 7017 7018 7019 7020 7021 7025 7059 7060 7061 7082 7084 7085 7089 7108 + 04 7018 7019 7020 7021 7025 7059 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 + 05 7018 7019 7020 7021 7025 7059 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 + 06 7020 7021 7025 7059 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 7112 7142 + 07 7025 7059 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 + 08 7059 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 + 09 7060 7061 7082 7084 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 + 10 7061 7082 7084 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 + 11 7084 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 + 12 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 + 13 7085 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 + 14 7089 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 7217 + 15 7108 7113 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 7217 7245 + 16 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 7217 7245 7250 7261 + 17 6909 7000 7112 7142 7164 7173 7179 7190 7201 7209 6942 6985 7217 7245 7250 7261 + 18 7173 7179 7190 7201 7209 6942 6985 7217 7245 7250 7261 7289 7314 7319 7325 7360 + 19 7179 7190 7201 7209 6942 6985 7217 7245 7250 7261 7289 7314 7319 7325 7360 7379 + 20 7190 7201 7209 6942 6985 7217 7245 7250 7261 7289 7314 7319 7325 7360 7379 7188 + 21 7209 6942 6985 7217 7245 7250 7261 7289 7314 7319 7325 7360 7379 7188 7324 7388 + 22 7209 6942 6985 7217 7245 7250 7261 7289 7314 7319 7325 7360 7379 7188 7324 7388 + """, + '3': """ + 01 6974 6977 6978 6979 6983 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 + 02 6974 6977 6978 6979 6983 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 + 03 6977 6978 6979 6983 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 + 04 6979 6983 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 + 05 6979 6983 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 + 06 6986 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 + 07 6991 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 + 08 6992 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 + 09 6993 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 + 10 6995 6998 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 + 11 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 + 12 7022 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 + 13 7024 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 7214 + 14 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 7214 + 15 7058 7063 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 7214 7223 + 16 7081 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 7214 7223 7247 7257 + 17 7106 7119 6982 7136 7161 7170 7177 7186 7195 6937 6946 7214 7223 7247 7257 7272 + 18 7257 7272 7279 7287 7297 7300 7305 7318 7326 7332 7339 7341 7352 7359 7369 7373 + 19 7279 7287 7297 7300 7305 7318 7326 7332 7339 7341 7352 7359 7369 7373 7381 7383 + 20 7287 7297 7300 7305 7318 7326 7332 7339 7341 7352 7359 7369 7373 7381 7383 7259 + 21 7297 7300 7305 7318 7326 7332 7339 7341 7352 7359 7369 7373 7381 7383 7259 7389 + 22 7297 7300 7305 7318 7326 7332 7339 7341 7352 7359 7369 7373 7381 7383 7259 7389 + """, + '4': """ + 01 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 + 02 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 + 03 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 + 04 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 + 05 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 + 06 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 + 07 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 + 08 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 + 09 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 + 10 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 + 11 7008 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 + 12 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 + 13 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 + 14 7009 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 + 15 7010 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 7225 + 16 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 7225 7259 + 17 7011 7012 7013 7014 7015 7016 7080 7109 6915 7160 7172 7188 7205 7083 7225 7259 + 18 6915 7160 7172 7188 7205 7083 7225 7259 7278 7291 7317 7324 7345 7358 7364 7370 + """, + '5': """ + 01 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 + 02 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 + 03 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 + 04 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 + 05 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 + 06 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 7143 + 07 7033 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 7143 7167 + 08 7034 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 7143 7167 7180 + 09 7035 7036 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 7143 7167 7180 7185 + 10 7037 7038 7039 7040 7041 7086 7110 7116 6910 7088 7143 7167 7180 7185 7194 7200 + 11 7041 7086 7110 7116 6910 7088 7143 7167 7180 7185 7194 7200 7206 7207 6939 6944 + 12 7116 6910 7088 7143 7167 7180 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 + 13 6910 7088 7143 7167 7180 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 7211 + 14 7088 7143 7167 7180 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 7211 7220 + 15 7143 7167 7180 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 7211 7220 7224 + 16 7180 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 7211 7220 7224 7246 7263 + 17 7185 7194 7200 7206 7207 6939 6944 6950 6951 6953 7211 7220 7224 7246 7263 7268 + 18 7220 7224 7246 7263 7268 7275 7283 7296 7308 7321 7330 7335 7336 7349 7353 7371 + 19 7224 7246 7263 7268 7275 7283 7296 7308 7321 7330 7335 7336 7349 7353 7371 6915 + 20 7224 7246 7263 7268 7275 7283 7296 7308 7321 7330 7335 7336 7349 7353 7371 6915 + 21 7268 7275 7283 7296 7308 7321 7330 7335 7336 7349 7353 7371 6915 7385 7391 7392 + 22 7283 7296 7308 7321 7330 7335 7336 7349 7353 7371 6915 7385 7391 7392 7400 7408 + """, + '6': """ + 01 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 + 02 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 + 03 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7087 + 04 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7087 7115 6940 + 05 7049 7050 7051 7052 7053 7054 7055 7056 7057 7087 7115 6940 + 06 7051 7052 7053 7054 7055 7056 7057 7087 7115 6940 7141 + 07 7052 7053 7054 7055 7056 7057 7087 7115 6940 7141 + 08 7054 7055 7056 7057 7087 7115 6940 7141 7176 + 09 7055 7056 7057 7087 7115 6940 7141 7176 + 10 7056 7057 7087 7115 6940 7141 7176 + 11 7057 7087 7115 6940 7141 7176 + 12 7087 7115 6940 7141 7176 + 13 6940 7141 7176 7213 + 14 7141 7176 7213 + 15 7141 7176 7213 + 16 7141 7176 7213 + 17 7141 7176 7213 + 18 7141 7176 7213 + 19 7176 7213 + 20 7176 7213 + 21 7213 + 22 + """, + '7': """ + 01 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 + 02 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 + 03 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 + 04 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 + 05 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 + 06 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 + 07 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 + 08 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 + 09 7071 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 + 10 7072 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 + 11 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 + 12 7073 7074 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 + 13 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 7210 7212 + 14 7075 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 7210 7212 + 15 7076 7077 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 7210 7212 7226 + 16 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 7210 7212 7226 7254 7265 + 17 7078 7079 7111 7118 6988 7139 7166 7175 7187 7198 6913 7210 7212 7226 7254 7265 + 18 6913 7210 7212 7226 7254 7265 7276 7284 7285 7293 7304 7306 7323 7333 7346 7355 + 19 7212 7226 7254 7265 7276 7284 7285 7293 7304 7306 7323 7333 7346 7355 7375 7083 + 20 7212 7226 7254 7265 7276 7284 7285 7293 7304 7306 7323 7333 7346 7355 7375 7083 + 21 7254 7265 7276 7284 7285 7293 7304 7306 7323 7333 7346 7355 7375 7083 7345 7395 + 22 7276 7284 7285 7293 7304 7306 7323 7333 7346 7355 7375 7083 7345 7395 7396 7405 + """, + '8': """ + 03 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 + 04 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7114 7117 6911 6948 7023 + 05 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7114 7117 6911 6948 7023 + 06 7097 7098 7099 7100 7101 7102 7103 7104 7105 7114 7117 6911 6948 7023 7137 7140 + 07 7099 7100 7101 7102 7103 7104 7105 7114 7117 6911 6948 7023 7137 7140 7162 7169 + 08 7100 7101 7102 7103 7104 7105 7114 7117 6911 6948 7023 7137 7140 7162 7169 7178 + 09 7103 7104 7105 7114 7117 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 + 10 7105 7114 7117 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 + 11 7114 7117 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 6920 + 12 7117 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 6920 6971 + 13 7117 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 6920 6971 + 14 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 6920 6971 7222 + 15 6911 6948 7023 7137 7140 7162 7169 7178 7182 7189 7191 7193 7199 6920 6971 7222 + 16 7162 7169 7178 7182 7189 7191 7193 7199 6920 6971 7222 7248 7249 7256 7260 7264 + 17 7169 7178 7182 7189 7191 7193 7199 6920 6971 7222 7248 7249 7256 7260 7264 7270 + 18 7199 6920 6971 7222 7248 7249 7256 7260 7264 7270 7280 7290 7309 7329 7348 7366 + 19 6971 7222 7248 7249 7256 7260 7264 7270 7280 7290 7309 7329 7348 7366 7380 7172 + 20 6971 7222 7248 7249 7256 7260 7264 7270 7280 7290 7309 7329 7348 7366 7380 7172 + 21 7248 7249 7256 7260 7264 7270 7280 7290 7309 7329 7348 7366 7380 7172 7291 7387 + 22 7260 7264 7270 7280 7290 7309 7329 7348 7366 7380 7172 7291 7387 7399 7402 7406 + """, + '9': """ + 04 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 + 05 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 7107 + 06 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 7107 7138 + 07 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 7107 7138 7168 + 08 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 7107 7138 7168 7181 + 09 7127 7128 7129 7130 7131 7132 7133 7134 7135 6919 7062 7107 7138 7168 7181 7184 + 10 7131 7132 7133 7134 7135 6919 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 + 11 7132 7133 7134 7135 6919 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 7208 + 12 7134 7135 6919 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 + 13 7135 6919 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 7215 + 14 6919 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 7215 7219 + 15 7062 7107 7138 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 7215 7219 7244 + 16 7138 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 7215 7219 7244 7252 7262 + 17 7168 7181 7184 7196 7197 7202 7204 7208 6947 6976 7215 7219 7244 7252 7262 7269 + 18 7215 7219 7244 7252 7262 7269 7286 7301 7313 7328 7337 7340 7351 7362 7367 7372 + 19 7244 7252 7262 7269 7286 7301 7313 7328 7337 7340 7351 7362 7367 7372 7382 7160 + 20 7252 7262 7269 7286 7301 7313 7328 7337 7340 7351 7362 7367 7372 7382 7160 7205 + 21 7301 7313 7328 7337 7340 7351 7362 7367 7372 7382 7160 7205 7278 7370 7390 7393 + 22 7337 7340 7351 7362 7367 7372 7382 7160 7205 7278 7370 7390 7393 7397 7404 7407 + """, + '10': """ + 06 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 + 07 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 + 08 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 + 09 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 + 10 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 + 11 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 + 12 7151 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 7183 + 13 7152 7153 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 7183 7216 + 14 7154 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 7183 7216 7218 7221 + 15 7155 7156 7157 7158 7159 7163 7165 7171 7174 7192 7203 7183 7216 7218 7221 7227 + 16 7158 7159 7163 7165 7171 7174 7192 7203 7183 7216 7218 7221 7227 7251 7258 7267 + 17 7159 7163 7165 7171 7174 7192 7203 7183 7216 7218 7221 7227 7251 7258 7267 7273 + 18 7277 7282 7288 7294 7302 7312 7320 7327 7331 7338 7347 7354 7357 7361 7365 7368 + 19 7288 7294 7302 7312 7320 7327 7331 7338 7347 7354 7357 7361 7365 7368 7376 7378 + 20 7288 7294 7302 7312 7320 7327 7331 7338 7347 7354 7357 7361 7365 7368 7376 7378 + 21 7302 7312 7320 7327 7331 7338 7347 7354 7357 7361 7365 7368 7376 7378 7364 7394 + 22 7327 7331 7338 7347 7354 7357 7361 7365 7368 7376 7378 7364 7394 7401 7403 7410 + """, + '12': """ + 15 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 + 16 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7253 7266 + 17 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7253 7266 7274 + 18 7281 7292 7298 7299 7303 7307 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 + 19 7299 7303 7307 7310 7311 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 + 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 + 22 7316 7322 7334 7343 7344 7350 7356 7363 7374 7377 7384 7225 7317 7386 7398 7409 + """ + } + + def make_address_data(): + for line in fake_data.addresses.strip().split('\n'): + data = line.split(maxsplit=2) + yield (data[0], {k:v for k,v in zip(('id','addr','subver'),data)}) + + def make_iterations_data(): + for line in fake_data.iterations.strip().split('\n'): + data = line.split(maxsplit=1) + yield (data[0], data[1].split()) + + def make_blocks_data(iterations): + for peer,blocks_str in fake_data.blocks.items(): + iter_strs = dict([s.lstrip().split(maxsplit=1) for s in blocks_str.strip().split('\n') if ' ' in s]) + yield (peer,dict((i,iter_strs.get(i,'').split()) for i in iterations)) + + def make_data(): + address_data = dict(fake_data.make_address_data()) + iterations_data = dict(fake_data.make_iterations_data()) + blocks_data = dict(fake_data.make_blocks_data(iterations_data)) + + def make_peerinfo(peer_id,blocks,iter_no): + d = address_data[peer_id] + return { + 'id': int(d['id']), + 'addr': d['addr'], + 'subver': d['subver'], + 'inflight': [int(n)+830000 for n in blocks[iter_no]], + } + + def gen_data(): + for iter_no in iterations_data: + yield ( + iter_no, + [make_peerinfo(peer_id,blocks,iter_no) for peer_id,blocks in blocks_data.items() + if peer_id in iterations_data[iter_no] ] + ) + + fake_data.peerinfo = dict(gen_data()) + + async def get_info(self,rpc): + fake_data.gp_counter = (fake_data.gp_counter % 22) + 1 + return fake_data.peerinfo[f'{fake_data.gp_counter:02d}'] + + async def disconnect_node(self,rpc,addr): + from mmgen.exception import RPCFailure + fake_data.dn_counter += 1 + if fake_data.dn_counter % 2: + raise RPCFailure + else: + pass + +fake_data.make_data() + +Display.poll_secs = fake_data.poll_secs +Display.get_info = fake_data.get_info +Display.disconnect_node = fake_data.disconnect_node diff --git a/test/test-release.d/cfg.sh b/test/test-release.d/cfg.sh index 59db1dd..ba2f6ce 100755 --- a/test/test-release.d/cfg.sh +++ b/test/test-release.d/cfg.sh @@ -14,7 +14,7 @@ # mmnode-feeview - # mmnode-halving-calculator OK # mmnode-netrate - -# mmnode-peerblocks - +# mmnode-peerblocks OK # mmnode-ticker OK # mmnode-txfind - @@ -38,10 +38,10 @@ list_avail_tests() { } init_groups() { - dfl_tests='unit misc scripts btc_rt bch_rt ltc_rt' + dfl_tests='unit misc scripts btc btc_rt bch_rt ltc_rt' extra_tests='' - noalt_tests='unit misc scripts btc_rt' - quick_tests='unit misc scripts btc_rt' + noalt_tests='unit misc scripts btc btc_rt' + quick_tests='unit misc scripts btc btc_rt' qskip_tests='bch_rt ltc_rt' } @@ -61,6 +61,11 @@ init_tests() { t_scripts="- $test_py scripts" f_scripts='No-daemon script tests completed' + i_btc='Bitcoin fake RPC data' + s_btc="The following tests will test various scripts with fake RPC data" + t_btc="- $test_py main" + f_btc='Bitcoin fake RPC data tests completed' + i_btc_rt='Bitcoin regtest' s_btc_rt="The following tests will test various scripts using regtest mode" t_btc_rt="- $test_py regtest" diff --git a/test/test_py_d/cfg.py b/test/test_py_d/cfg.py index d2726c4..c2c72e3 100755 --- a/test/test_py_d/cfg.py +++ b/test/test_py_d/cfg.py @@ -15,6 +15,7 @@ test.test_py_d.cfg: configuration data for test.py import os cmd_groups_dfl = { + 'main': ('TestSuiteMain',{}), 'helpscreens': ('TestSuiteHelp',{'modname':'misc','full_data':True}), 'scripts': ('TestSuiteScripts',{'modname':'misc'}), 'regtest': ('TestSuiteRegtest',{}), @@ -25,6 +26,7 @@ cmd_groups_extra = {} cfgs = { '1': {}, # regtest '2': {}, # scripts + '3': {}, # main } def fixup_cfgs(): pass diff --git a/test/test_py_d/ts_main.py b/test/test_py_d/ts_main.py new file mode 100755 index 0000000..7974c58 --- /dev/null +++ b/test/test_py_d/ts_main.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# +# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet +# Copyright (C)2013-2022 The MMGen Project +# Licensed under the GNU General Public License, Version 3: +# https://www.gnu.org/licenses +# Public project repositories: +# https://github.com/mmgen/mmgen +# https://gitlab.com/mmgen/mmgen + +""" +test_py_d.ts_main: Basic operations tests for the test.py test suite +""" + +import time + +from ..include.common import * +from .common import * +from .ts_base import * + +class TestSuiteMain(TestSuiteBase): + 'basic operations with fake RPC data' + tmpdir_nums = [3] + networks = ('btc',) # fake data, so test peerblocks for BTC mainnet only + passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet','rpc_backend') + segwit_opts_ok = True + color = True + need_daemon = True + + cmd_group_in = ( + ('subgroup.peerblocks', []), + ) + + cmd_subgroups = { + 'peerblocks': ( + "'mmnode-peerblocks' script", + ('peerblocks1', '--help'), + ('peerblocks2', 'interactive'), + ('peerblocks3', 'interactive, 80 columns'), + ), + } + + def peerblocks(self,args,expect_list=None): + t = self.spawn( + f'mmnode-peerblocks', + args ) + if opt.exact_output: # disable echoing of input + t.p.logfile = None + t.p.logfile_read = sys.stdout + if expect_list: + t.match_expect_list(expect_list) + return t + + def peerblocks1(self): + t = self.peerblocks(['--help']) + if opt.pexpect_spawn: + t.send('q') + return t + + def peerblocks2(self,args=[]): + + t = self.peerblocks(args) + + for i in range(5): + t.expect('PEERS') + + t.send('x') + + for i in range(3): + t.expect('PEERS') + + t.send('0') + time.sleep(0.2) + t.send('\n') + t.expect('Unable to disconnect peer 0') + t.expect('PEERS') + + t.send('1') + time.sleep(0.2) + t.send('1\n') + t.expect('11: invalid peer number') + t.expect('PEERS') + + t.send('2') + time.sleep(0.2) + t.send('\n') + t.expect('Disconnecting peer 2') + t.expect('PEERS') + + t.send('q') + + return t + + def peerblocks3(self): + return self.peerblocks2(['--columns=80'])