diff --git a/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py b/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py index c46ed96e0..02ef4f25b 100644 --- a/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py +++ b/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py @@ -340,6 +340,12 @@ def SearchAssetState(self, query): assets = DBCollection(self._db, DBPrefix.ST_Asset, AssetState) keys = assets.Keys + if query.lower() == "neo": + query = "AntShare" + + if query.lower() in {"gas", "neogas"}: + query = "AntCoin" + for item in keys: asset = assets.TryGet(keyval=item) if query in asset.Name.decode('utf-8'): diff --git a/neo/Prompt/Commands/Search.py b/neo/Prompt/Commands/Search.py new file mode 100644 index 000000000..8c23e8aeb --- /dev/null +++ b/neo/Prompt/Commands/Search.py @@ -0,0 +1,69 @@ +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 neo.logging import log_manager +import json + + +logger = log_manager.getLogger() + + +class CommandSearch(CommandBase): + def __init__(self): + super().__init__() + + self.register_sub_command(CommandSearchAsset()) + self.register_sub_command(CommandSearchContract()) + + def command_desc(self): + return CommandDesc('search', 'search the blockchain') + + def execute(self, arguments): + item = get_arg(arguments) + + if not item: + print("run `%s help` to see supported queries" % CommandSearch().command_desc().command) + return + + try: + return self.execute_sub_command(item, arguments[1:]) + except KeyError: + print(f"{item} is an invalid parameter") + return + + +class CommandSearchAsset(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + item = get_arg(arguments) + + results = Blockchain.Default().SearchAssetState(item) + print("Found %s results for %s" % (len(results), item)) + for asset in results: + print(json.dumps(asset.ToJson(), indent=4)) + return results + + def command_desc(self): + p1 = ParameterDesc('query', 'supports name, issuer, or admin searches') + return CommandDesc('asset', 'perform an asset search', [p1]) + + +class CommandSearchContract(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + item = get_arg(arguments) + + contracts = Blockchain.Default().SearchContracts(query=item) + print("Found %s results for %s" % (len(contracts), item)) + for contract in contracts: + print(json.dumps(contract.ToJson(), indent=4)) + return contracts + + def command_desc(self): + p1 = ParameterDesc('query', 'supports name, author, description, or email searches') + return CommandDesc('contract', 'perform a contract search', [p1]) diff --git a/neo/Prompt/Commands/Wallet.py b/neo/Prompt/Commands/Wallet.py index 55639490b..a2cc19147 100644 --- a/neo/Prompt/Commands/Wallet.py +++ b/neo/Prompt/Commands/Wallet.py @@ -61,7 +61,7 @@ def execute(self, arguments): try: return self.execute_sub_command(item, arguments[1:]) except KeyError: - print(f"Wallet: {item} is an invalid parameter") + print(f"{item} is an invalid parameter") return diff --git a/neo/Prompt/Commands/tests/test_search_commands.py b/neo/Prompt/Commands/tests/test_search_commands.py new file mode 100644 index 000000000..b591aaf96 --- /dev/null +++ b/neo/Prompt/Commands/tests/test_search_commands.py @@ -0,0 +1,87 @@ +import os +from neo.Settings import settings +from neo.Utils.BlockchainFixtureTestCase import BlockchainFixtureTestCase +from neo.Prompt.Commands.Search import CommandSearch + + +class CommandShowTestCase(BlockchainFixtureTestCase): + + @classmethod + def leveldb_testpath(self): + return os.path.join(settings.DATA_DIR_PATH, 'fixtures/test_chain') + + def test_search(self): + # with no subcommand + res = CommandSearch().execute(None) + self.assertFalse(res) + + # with invalid command + args = ['badcommand'] + res = CommandSearch().execute(args) + self.assertFalse(res) + + def test_search_asset(self): + # successful search asset NEO + args = ['asset', "NEO"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # successful search asset gas + args = ['asset', "gas"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # successful search asset NEOGas + args = ['asset', "NEOGas"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # successful search asset AntShare + args = ['asset', "AntShare"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # successful search asset AntCoin + args = ['asset', "AntCoin"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # successful search by issuer and admin (same address) + args = ['asset', "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt"] + res = CommandSearch().execute(args) + self.assertTrue(res) + + # unsuccessful search + args = ['asset', 'blah'] + res = CommandSearch().execute(args) + self.assertFalse(res) + + def test_search_contract(self): + # successful search by name + args = ['contract', "test NEX Template V4"] + res = CommandSearch().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + + # successful search by author + args = ['contract', "dauTT"] + res = CommandSearch().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 3) + + # successful search by description + args = ['contract', "neo-ico-template"] + res = CommandSearch().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + + # successful search by email (as entered) + args = ['contract', ""] + res = CommandSearch().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 6) + + # bad search input + args = ['contract', "blah"] + res = CommandSearch().execute(args) + self.assertFalse(res) diff --git a/neo/bin/prompt.py b/neo/bin/prompt.py index a955e0c83..6cbf1f489 100755 --- a/neo/bin/prompt.py +++ b/neo/bin/prompt.py @@ -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.Search import CommandSearch from neo.Prompt.PromptData import PromptData from neo.Prompt.InputParser import InputParser from neo.Settings import settings, PrivnetConnectionError @@ -70,7 +71,7 @@ class PromptInterface: _known_things = [] _commands = [ - CommandWallet(), + CommandWallet(), CommandSearch() ] _command_descs = [desc for c in _commands for desc in c.command_descs_with_sub_commands()]