Skip to content
This repository was archived by the owner on Nov 15, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion neo/Prompt/Commands/Search.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def execute(self, arguments):
item = get_arg(arguments)

if not item:
print("run `%s help` to see supported queries" % CommandSearch().command_desc().command)
print("run `%s help` to see supported queries" % self.command_desc().command)
return

try:
Expand Down
169 changes: 169 additions & 0 deletions neo/Prompt/Commands/Show.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import os
import psutil
import datetime
from neo.Prompt.CommandBase import CommandBase, CommandDesc, ParameterDesc
from neo.Prompt.PromptData import PromptData
from neo.Prompt.Utils import get_arg
from neo.Core.Blockchain import Blockchain
from neocore.UInt256 import UInt256
from neo.IO.MemoryStream import StreamManager
from neo.Network.NodeLeader import NodeLeader
from neo.Implementations.Notifications.LevelDB.NotificationDB import NotificationDB
from neo.logging import log_manager
import json


logger = log_manager.getLogger()


class CommandShow(CommandBase):
def __init__(self):
super().__init__()

self.register_sub_command(CommandShowBlock())
self.register_sub_command(CommandShowHeader())
self.register_sub_command(CommandShowTx())
self.register_sub_command(CommandShowMem())
self.register_sub_command(CommandShowNodes(), ['node'])

def command_desc(self):
return CommandDesc('show', 'show useful data')

def execute(self, arguments):
item = get_arg(arguments)

if not item:
print("run `%s help` to see supported queries" % self.command_desc().command)
return

try:
return self.execute_sub_command(item, arguments[1:])
except KeyError:
print(f"{item} is an invalid parameter")
return


class CommandShowBlock(CommandBase):
def __init__(self):
super().__init__()

def execute(self, arguments):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show block and show headers without an argument throws an exception. Example

neo> show block
Could not execute command: object of type 'NoneType' has no len()
and then some

show tx without arguments throws a different exception

neo> show tx
Could not find transaction from args: 'NoneType' object is not subscriptable ([])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed all those user friendly messages because I thought @LysanderGG 's change to CommandBase here #733 (review) was going to be merged. Oops 😊
I will add all the original messages back in

item = get_arg(arguments)
txarg = get_arg(arguments, 1)
if item is not None:
block = Blockchain.Default().GetBlock(item)

if block is not None:
block.LoadTransactions()

if txarg and 'tx' in txarg:
txs = []
for tx in block.FullTransactions:
print(json.dumps(tx.ToJson(), indent=4))
txs.append(tx.ToJson())
return txs

print(json.dumps(block.ToJson(), indent=4))
return block.ToJson()

else:
print("Could not locate block %s" % item)
return
else:
print("please specify a block")
return

def command_desc(self):
p1 = ParameterDesc('index/hash', 'the index or scripthash of the block')
p2 = ParameterDesc('tx', 'arg to only show block transactions', optional=True)
return CommandDesc('block', 'show a specified block', [p1, p2])


class CommandShowHeader(CommandBase):
def __init__(self):
super().__init__()

def execute(self, arguments):
item = get_arg(arguments)
if item is not None:
header = Blockchain.Default().GetHeaderBy(item)
if header is not None:
print(json.dumps(header.ToJson(), indent=4))
return header.ToJson()
else:
print("Could not locate header %s\n" % item)
return
else:
print("Please specify a header")
return

def command_desc(self):
p1 = ParameterDesc('index/hash', 'the index or scripthash of the block header')
return CommandDesc('header', 'show the header of a specified block', [p1])


class CommandShowTx(CommandBase):
def __init__(self):
super().__init__()

def execute(self, arguments):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show tx with an invalid argument gives a not user friendly error

neo> show tx 1
Could not find transaction from args: Invalid UInt256 Format: 1 chars != 64 chars (['1'])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about now? (I just removed the exception)

if len(arguments):
try:
txid = UInt256.ParseString(get_arg(arguments))
tx, height = Blockchain.Default().GetTransaction(txid)
if height > -1:
jsn = tx.ToJson()
jsn['height'] = height
jsn['unspents'] = [uns.ToJson(tx.outputs.index(uns)) for uns in
Blockchain.Default().GetAllUnspent(txid)]
print(json.dumps(jsn, indent=4))
return jsn
else:
print(f"Could not find transaction for hash {txid}")
return
except Exception:
print("Could not find transaction from args: %s" % arguments)
return
else:
print("Please specify a TX hash")
return

def command_desc(self):
p1 = ParameterDesc('hash', 'the scripthash of the transaction')
return CommandDesc('tx', 'show a specified transaction', [p1])


class CommandShowMem(CommandBase):
def __init__(self):
super().__init__()

def execute(self, arguments=None):
process = psutil.Process(os.getpid())
total = process.memory_info().rss
totalmb = total / (1024 * 1024)
out = "Total: %s MB\n" % totalmb
out += "Total buffers: %s\n" % StreamManager.TotalBuffers()
print(out)
return out

def command_desc(self):
return CommandDesc('mem', 'show memory in use and number of buffers')


class CommandShowNodes(CommandBase):
def __init__(self):
super().__init__()

def execute(self, arguments=None):
if len(NodeLeader.Instance().Peers) > 0:
out = "Total Connected: %s\n" % len(NodeLeader.Instance().Peers)
for peer in NodeLeader.Instance().Peers:
out += "Peer %s - IO: %s\n" % (peer.Name(), peer.IOStats())
print(out)
return out
else:
print("Not connected yet\n")
return

def command_desc(self):
return CommandDesc('nodes', 'show connected peers')
158 changes: 158 additions & 0 deletions neo/Prompt/Commands/tests/test_show_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import os
from neo.Settings import settings
from neo.Utils.BlockchainFixtureTestCase import BlockchainFixtureTestCase
from neo.Prompt.Commands.Show import CommandShow
from neo.Prompt.Commands.Wallet import CommandWallet
from neo.Prompt.PromptData import PromptData
from neo.bin.prompt import PromptInterface
from copy import deepcopy
from neo.Network.NodeLeader import NodeLeader, NeoNode
from neo.Core.Blockchain import Blockchain
from neo.Implementations.Wallets.peewee.UserWallet import UserWallet
from mock import patch


class CommandShowTestCase(BlockchainFixtureTestCase):

@classmethod
def leveldb_testpath(self):
return os.path.join(settings.DATA_DIR_PATH, 'fixtures/test_chain')

@classmethod
def tearDown(cls):
PromptData.Prompt = None
PromptData.Wallet = None

def test_show(self):
# with no subcommand
res = CommandShow().execute(None)
self.assertFalse(res)

# with invalid command
args = ['badcommand']
res = CommandShow().execute(args)
self.assertFalse(res)

def test_show_block(self):
# test no block input
args = ['block']
res = CommandShow().execute(args)
self.assertFalse(res)

# show good block by index
args = ['block', '9']
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(res['index'], 9)
self.assertIn('tx', res)

# show good block by hash
args = ['block', "0x7c5b4c8a70336bf68e8679be7c9a2a15f85c0f6d0e14389019dcc3edfab2bb4b"]
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(res['index'], 9)
self.assertIn('tx', res)

# show the block's transactions only
args = ['block', '9', "tx"]
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(len(res), 2)
self.assertEqual(res[0]['type'], "MinerTransaction")
self.assertEqual(res[1]['type'], "ContractTransaction")

# request bad block
args = ['block', 'blah']
res = CommandShow().execute(args)
self.assertFalse(res)

def test_show_header(self):
# test no header input
args = ['header']
res = CommandShow().execute(args)
self.assertFalse(res)

# show good header by index
args = ['header', '9']
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(res['index'], 9)
self.assertNotIn('tx', res)

# show good header by hash
args = ['header', "0x7c5b4c8a70336bf68e8679be7c9a2a15f85c0f6d0e14389019dcc3edfab2bb4b"]
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(res['index'], 9)
self.assertNotIn('tx', res)

# request bad header
args = ['header', 'blah']
res = CommandShow().execute(args)
self.assertFalse(res)

def test_show_tx(self):
# test no tx input
args = ['tx']
res = CommandShow().execute(args)
self.assertFalse(res)

# show good tx
txid = '0x83df8bd085fcb60b2789f7d0a9f876e5f3908567f7877fcba835e899b9dea0b5'
args = ['tx', txid]
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertEqual(res['txid'], txid)
self.assertIn('height', res)
self.assertIn('unspents', res)

# query a bad tx
args = ['tx', '0x83df8bd085fcb60b2789f7d0a9f876e5f3908567f7877fcba835e899b9dea0b6']
res = CommandShow().execute(args)
self.assertFalse(res)

# query with bad args
args = ['tx', 'blah']
res = CommandShow().execute(args)
self.assertFalse(res)

def test_show_mem(self):
args = ['mem']
res = CommandShow().execute(args)
self.assertTrue(res)

def test_show_nodes(self):
# query nodes with no NodeLeader.Instance()
with patch('neo.Network.NodeLeader.NodeLeader.Instance'):
args = ['nodes']
res = CommandShow().execute(args)
self.assertFalse(res)

# query nodes with connected peers
# first make sure we have a predictable state
leader = NodeLeader.Instance()
old_leader = deepcopy(leader)
leader.ADDRS = ["127.0.0.1:20333", "127.0.0.2:20334"]
leader.DEAD_ADDRS = ["127.0.0.1:20335"]
test_node = NeoNode()
test_node.host = "127.0.0.1"
test_node.port = 20333
leader.Peers = [test_node]

# now show nodes
with patch('neo.Network.NeoNode.NeoNode.Name', return_value="test name"):
args = ['nodes']
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertIn('Total Connected: 1', res)
self.assertIn('Peer test name - IO: 0.0 MB in / 0.0 MB out', res)

# now use "node"
args = ['node']
res = CommandShow().execute(args)
self.assertTrue(res)
self.assertIn('Total Connected: 1', res)
self.assertIn('Peer test name - IO: 0.0 MB in / 0.0 MB out', res)

# restore whatever state the instance was in
NodeLeader._LEAD = old_leader
3 changes: 2 additions & 1 deletion neo/bin/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from neo.Implementations.Notifications.LevelDB.NotificationDB import NotificationDB
from neo.Network.NodeLeader import NodeLeader
from neo.Prompt.Commands.Wallet import CommandWallet
from neo.Prompt.Commands.Show import CommandShow
from neo.Prompt.Commands.Search import CommandSearch
from neo.Prompt.PromptData import PromptData
from neo.Prompt.InputParser import InputParser
Expand Down Expand Up @@ -71,7 +72,7 @@ class PromptInterface:
_known_things = []

_commands = [
CommandWallet(), CommandSearch()
CommandWallet(), CommandShow(), CommandSearch()
]

_command_descs = [desc for c in _commands for desc in c.command_descs_with_sub_commands()]
Expand Down