From 681b063cf7e9e64da30bacc5fafca1145601085a Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Tue, 4 Dec 2018 04:57:34 -0800 Subject: [PATCH 01/19] Update prompt.py - add CommandShow and CommandSearch to prompt --- neo/bin/prompt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/neo/bin/prompt.py b/neo/bin/prompt.py index a955e0c83..e8d0290a9 100755 --- a/neo/bin/prompt.py +++ b/neo/bin/prompt.py @@ -16,6 +16,8 @@ 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 from neo.Settings import settings, PrivnetConnectionError @@ -70,7 +72,7 @@ class PromptInterface: _known_things = [] _commands = [ - CommandWallet(), + CommandWallet(), CommandShow(), CommandSearch() ] _command_descs = [desc for c in _commands for desc in c.command_descs_with_sub_commands()] From 5b8c2268ea3746b5c69d08cbdfdc23bb3b07ab74 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Tue, 4 Dec 2018 04:58:26 -0800 Subject: [PATCH 02/19] Update prompt.py revert changes --- neo/bin/prompt.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/neo/bin/prompt.py b/neo/bin/prompt.py index e8d0290a9..a955e0c83 100755 --- a/neo/bin/prompt.py +++ b/neo/bin/prompt.py @@ -16,8 +16,6 @@ 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 from neo.Settings import settings, PrivnetConnectionError @@ -72,7 +70,7 @@ class PromptInterface: _known_things = [] _commands = [ - CommandWallet(), CommandShow(), CommandSearch() + CommandWallet(), ] _command_descs = [desc for c in _commands for desc in c.command_descs_with_sub_commands()] From a3cada592f417fe4d2ae56f3d634977d3dac430c Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 06:46:59 -0800 Subject: [PATCH 03/19] Update Show.py - add the remaining show methods --- neo/Prompt/Commands/Show.py | 173 ++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/neo/Prompt/Commands/Show.py b/neo/Prompt/Commands/Show.py index b3214ad1f..37934ade5 100644 --- a/neo/Prompt/Commands/Show.py +++ b/neo/Prompt/Commands/Show.py @@ -25,6 +25,11 @@ def __init__(self): self.register_sub_command(CommandShowTx()) self.register_sub_command(CommandShowMem()) self.register_sub_command(CommandShowNodes(), ['node']) + self.register_sub_command(CommandShowState()) + self.register_sub_command(CommandShowNotifications()) + self.register_sub_command(CommandShowAccount()) + self.register_sub_command(CommandShowAsset()) + self.register_sub_command(CommandShowContract()) def command_desc(self): return CommandDesc('show', 'show useful data') @@ -167,3 +172,171 @@ def execute(self, arguments=None): def command_desc(self): return CommandDesc('nodes', 'show connected peers') + + +class CommandShowState(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments=None): + height = Blockchain.Default().Height + headers = Blockchain.Default().HeaderHeight + + diff = height - PromptData.Prompt.start_height + now = datetime.datetime.utcnow() + difftime = now - PromptData.Prompt.start_dt + + mins = difftime / datetime.timedelta(minutes=1) + secs = mins * 60 + + bpm = 0 + tps = 0 + if diff > 0 and mins > 0: + bpm = diff / mins + tps = Blockchain.Default().TXProcessed / secs + + out = "Progress: %s / %s\n" % (height, headers) + out += "Block-cache length %s\n" % Blockchain.Default().BlockCacheCount + out += "Blocks since program start %s\n" % diff + out += "Time elapsed %s mins\n" % mins + out += "Blocks per min %s \n" % bpm + out += "TPS: %s \n" % tps + print(out) + return out + + def command_desc(self): + return CommandDesc('state', 'show the status of the node') + + +class CommandShowNotifications(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + if NotificationDB.instance() is None: + print("No notification DB Configured") + return + + item = get_arg(arguments, 0) + events = [] + if len(item) == 34 and item[0] == 'A': + addr = item + events = NotificationDB.instance().get_by_addr(addr) + else: + try: + block_height = int(item) + if block_height < Blockchain.Default().Height: + events = NotificationDB.instance().get_by_block(block_height) + else: + print("Block %s not found" % block_height) + return + except Exception as e: + print("Could not parse block height %s" % e) + return + + if len(events): + [print(json.dumps(e.ToJson(), indent=4)) for e in events] + return events + else: + print("No events found for %s" % item) + return + + def command_desc(self): + p1 = ParameterDesc('block_index/address', 'the block or address to show notifications for') + return CommandDesc('notifications', 'show specified contract execution notifications', [p1]) + + +class CommandShowAccount(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + item = get_arg(arguments) + if item is not None: + account = Blockchain.Default().GetAccountState(item, print_all_accounts=True) + + if account is not None: + print(json.dumps(account.ToJson(), indent=4)) + return account.ToJson() + else: + print("Account %s not found" % item) + return + else: + print("Please specify an account address") + return + + def command_desc(self): + p1 = ParameterDesc('address', 'the address to show') + return CommandDesc('account', 'show the assets (NEO/GAS) held by a specified address', [p1]) + + +class CommandShowAsset(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + item = get_arg(arguments) + if item is not None: + if item.lower() == "all": + assets = Blockchain.Default().ShowAllAssets() + print("Assets: %s" % assets) + return assets + + if item.lower() == 'neo': + assetId = Blockchain.Default().SystemShare().Hash + elif item.lower() == 'gas': + assetId = Blockchain.Default().SystemCoin().Hash + else: + try: + assetId = UInt256.ParseString(item) + except Exception as e: + print("Could not find assetId from args: %s (%s)" % (e, arguments)) + return + + asset = Blockchain.Default().GetAssetState(assetId.ToBytes()) + + if asset is not None: + print(json.dumps(asset.ToJson(), indent=4)) + return asset.ToJson() + else: + print("Asset %s not found" % item) + return + else: + print("Please specify an asset hash or name") + return + + def command_desc(self): + p1 = ParameterDesc('name/assetId/all', 'the name or assetId of the asset, or "all" shows all assets\n\n') + f"{' ':>17} Example:\n" + f"{' ':>20} 'neo' or 'c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b'\n" + f"{' ':>20} 'gas' or '602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7'\n" + return CommandDesc('asset', 'show a specified asset', [p1]) + + +class CommandShowContract(CommandBase): + def __init__(self): + super().__init__() + + def execute(self, arguments): + item = get_arg(arguments) + if item is not None: + if item.lower() == "all": + contracts = Blockchain.Default().ShowAllContracts() + print("Contracts: %s" % contracts) + return contracts + + contract = Blockchain.Default().GetContract(item) + + if contract is not None: + contract.DetermineIsNEP5() + print(json.dumps(contract.ToJson(), indent=4)) + return contract.ToJson() + else: + print("Contract %s not found" % item) + return + else: + print("Please specify a contract") + + def command_desc(self): + p1 = ParameterDesc('hash/all', 'the scripthash of the contract, or "all" shows all contracts') + return CommandDesc('contract', 'show a specified smart contract', [p1]) From 929bbfa9a82f169c84985477715b4ad467d47665 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 06:49:03 -0800 Subject: [PATCH 04/19] Update test_show_commands.py - add tests for remaining show methods --- .../Commands/tests/test_show_commands.py | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/neo/Prompt/Commands/tests/test_show_commands.py b/neo/Prompt/Commands/tests/test_show_commands.py index a297abc0c..c3447beab 100644 --- a/neo/Prompt/Commands/tests/test_show_commands.py +++ b/neo/Prompt/Commands/tests/test_show_commands.py @@ -156,3 +156,157 @@ def test_show_nodes(self): # restore whatever state the instance was in NodeLeader._LEAD = old_leader + + def test_show_state(self): + # setup + PromptInterface() + + args = ['state'] + res = CommandShow().execute(args) + self.assertTrue(res) + + def test_show_notifications(self): + # setup + wallet_1_addr = 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3' + + # test with no NotificationDB + with patch('neo.Implementations.Notifications.LevelDB.NotificationDB.NotificationDB.instance', return_value=None): + args = ['notifications', wallet_1_addr] + res = CommandShow().execute(args) + self.assertFalse(res) + + # good test with address + args = ['notifications', wallet_1_addr] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + jsn = res[0].ToJson() + self.assertEqual(jsn['notify_type'], 'transfer') + self.assertEqual(jsn['addr_from'], wallet_1_addr) + + # test an address with no notifications + args = ['notifications', 'AZiE7xfyJALW7KmADWtCJXGGcnduYhGiCX'] + res = CommandShow().execute(args) + self.assertFalse(res) + + # good test with block index + args = ['notifications', "12337"] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + jsn = res[0].ToJson() + self.assertEqual(jsn['notify_type'], 'transfer') + self.assertEqual(jsn['block'], 12337) + + # test bad block + index = Blockchain.Default().Height + 1 + args = ['notifications', str(index)] + res = CommandShow().execute(args) + self.assertFalse(res) + + # test invalid block input + args = ['notifications', "blah"] + res = CommandShow().execute(args) + self.assertFalse(res) + + def test_show_account(self): + # setup + wallet_1_addr = 'AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3' + + # test no account address entered + args = ['account'] + res = CommandShow().execute(args) + self.assertFalse(res) + + # test good account + args = ['account', wallet_1_addr] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(res['address'], wallet_1_addr) + self.assertIn('balances', res) + + # test empty account + with patch('neo.Prompt.PromptData.PromptData.Prompt'): + with patch('neo.Prompt.Commands.Wallet.prompt', side_effect=["testpassword", "testpassword"]): + args = ['create', 'testwallet.wallet'] + res = CommandWallet().execute(args) + self.assertTrue(res) + self.assertIsInstance(res, UserWallet) + + addr = res.Addresses[0] + args = ['account', addr] + res = CommandShow().execute(args) + self.assertFalse(res) + + # remove test wallet + os.remove("testwallet.wallet") + + def test_show_asset(self): + # test no asset entered + args = ['asset'] + res = CommandShow().execute(args) + self.assertFalse(res) + + # show all assets + args = ['asset', 'all'] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertIn("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7", str(res)) + self.assertIn("c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", str(res)) + + # query with "neo" + args = ['asset', 'neo'] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(res['assetId'], "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b") + self.assertEqual(res['name'], "NEO") + + # query with "gas" + args = ['asset', 'gas'] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(res['assetId'], "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7") + self.assertEqual(res['name'], "NEOGas") + + # query with scripthash + args = ['asset', 'c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b'] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(res['assetId'], "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b") + self.assertEqual(res['name'], "NEO") + + # query with bad asset + args = ['asset', 'c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9e'] + res = CommandShow().execute(args) + self.assertFalse(res) + + # query with bad input + args = ['asset', 'blah'] + res = CommandShow().execute(args) + self.assertFalse(res) + + def test_show_contract(self): + # test no contract entered + args = ['contract'] + res = CommandShow().execute(args) + self.assertFalse(res) + + # show all contracts + args = ['contract', 'all'] + res = CommandShow().execute(args) + self.assertTrue(res) + res = list(res) + self.assertEqual(len(res), 6) + + # query with contract scripthash + args = ['contract', '31730cc9a1844891a3bafd1aa929a4142860d8d3'] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(res['name'], "test NEX Template V4") + self.assertEqual(res['token']['name'], "NEX Template V4") + self.assertEqual(res['token']['symbol'], "NXT4") + + # query bad input + args = ['contract', 'blah'] + res = CommandShow().execute(args) + self.assertFalse(res) From f9f6bd4aceefcbcc08e15922ef1f1ef32416138b Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 06:50:12 -0800 Subject: [PATCH 05/19] Update LevelDBBlockchain.py add ShowAllAssets --- .../Blockchains/LevelDB/LevelDBBlockchain.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py b/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py index 02ef4f25b..33732f80b 100644 --- a/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py +++ b/neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py @@ -371,6 +371,12 @@ def GetAssetState(self, assetId): return asset + def ShowAllAssets(self): + + assets = DBCollection(self._db, DBPrefix.ST_Asset, AssetState) + keys = assets.Keys + return keys + def GetTransaction(self, hash): if type(hash) is str: From f8af38c3e1f00de00ff47321954d3bf7b22760eb Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 06:50:58 -0800 Subject: [PATCH 06/19] Update test_LevelDBBlockchain.py - add a test for ShowAllAssets --- .../Blockchains/LevelDB/test_LevelDBBlockchain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py b/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py index 48155c5ea..c16f233f8 100644 --- a/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py +++ b/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py @@ -74,3 +74,7 @@ def test_GetHeaderBy(self): invalid_bc_height = self._blockchain.Height + 1 block = self._blockchain.GetHeaderBy(invalid_bc_height) self.assertEqual(block, None) + + def test_ShowAllAssets(self): + assets = Blockchain.Default().ShowAllAssets() + self.assertEqual(len(assets), 2) From af03ed611f6fdab80e741a73141c29811ef92c8b Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 06:52:41 -0800 Subject: [PATCH 07/19] Update Blockchain.py - add ShowAllAssets --- neo/Core/Blockchain.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/neo/Core/Blockchain.py b/neo/Core/Blockchain.py index 88ee05b20..242a6ad9b 100644 --- a/neo/Core/Blockchain.py +++ b/neo/Core/Blockchain.py @@ -308,6 +308,9 @@ def GetAssetState(self, assetId): def SearchAssetState(self, query): pass + def ShowAllAssets(self): + pass + def GetHeaderHash(self, height): pass From 8c064d8b6d36ed1e2914751b96b19530e7cab4b6 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Thu, 6 Dec 2018 07:04:34 -0800 Subject: [PATCH 08/19] Update test_LevelDBBlockchain.py - fixed indentation --- .../Blockchains/LevelDB/test_LevelDBBlockchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py b/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py index c16f233f8..2277321c0 100644 --- a/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py +++ b/neo/Implementations/Blockchains/LevelDB/test_LevelDBBlockchain.py @@ -75,6 +75,6 @@ def test_GetHeaderBy(self): block = self._blockchain.GetHeaderBy(invalid_bc_height) self.assertEqual(block, None) - def test_ShowAllAssets(self): + def test_ShowAllAssets(self): assets = Blockchain.Default().ShowAllAssets() self.assertEqual(len(assets), 2) From b6b330b3830999a188cf0b5bfa154381b761acbf Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Sat, 8 Dec 2018 01:16:02 -0800 Subject: [PATCH 09/19] Update Show.py - update methods per https://github.com/CityOfZion/neo-python/pull/741#pullrequestreview-182635424 --- neo/Prompt/Commands/Show.py | 65 ++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/neo/Prompt/Commands/Show.py b/neo/Prompt/Commands/Show.py index 37934ade5..caf6091d4 100644 --- a/neo/Prompt/Commands/Show.py +++ b/neo/Prompt/Commands/Show.py @@ -6,6 +6,7 @@ from neo.Prompt.Utils import get_arg from neo.Core.Blockchain import Blockchain from neocore.UInt256 import UInt256 +from neocore.UInt160 import UInt160 from neo.IO.MemoryStream import StreamManager from neo.Network.NodeLeader import NodeLeader from neo.Implementations.Notifications.LevelDB.NotificationDB import NotificationDB @@ -217,32 +218,43 @@ def execute(self, arguments): print("No notification DB Configured") return - item = get_arg(arguments, 0) - events = [] - if len(item) == 34 and item[0] == 'A': - addr = item - events = NotificationDB.instance().get_by_addr(addr) - else: - try: - block_height = int(item) - if block_height < Blockchain.Default().Height: - events = NotificationDB.instance().get_by_block(block_height) - else: - print("Block %s not found" % block_height) + item = get_arg(arguments) + if item is not None: + if item[0:2] == "0x": + item = item[2:] + + events = [] + + if len(item) == 34 and item[0] == 'A': + events = NotificationDB.instance().get_by_addr(item) + + elif len(item) == 40: + events = NotificationDB.instance().get_by_contract(item) + + else: + try: + block_height = int(item) + if block_height < Blockchain.Default().Height: + events = NotificationDB.instance().get_by_block(block_height) + else: + print("Block %s not found" % block_height) + return + except Exception: + print("Could not find notifications from args: %s" % arguments) return - except Exception as e: - print("Could not parse block height %s" % e) - return - if len(events): - [print(json.dumps(e.ToJson(), indent=4)) for e in events] - return events + if len(events): + [print(json.dumps(e.ToJson(), indent=4)) for e in events] + return events + else: + print("No events found for %s" % item) + return else: - print("No events found for %s" % item) + print("Please specify a block index, address, or contract hash") return def command_desc(self): - p1 = ParameterDesc('block_index/address', 'the block or address to show notifications for') + p1 = ParameterDesc('block_index/address/contract_hash', 'the block, address, or contract to show notifications for') return CommandDesc('notifications', 'show specified contract execution notifications', [p1]) @@ -289,8 +301,8 @@ def execute(self, arguments): else: try: assetId = UInt256.ParseString(item) - except Exception as e: - print("Could not find assetId from args: %s (%s)" % (e, arguments)) + except Exception: + print("Could not find asset from args: %s" % arguments) return asset = Blockchain.Default().GetAssetState(assetId.ToBytes()) @@ -325,7 +337,13 @@ def execute(self, arguments): print("Contracts: %s" % contracts) return contracts - contract = Blockchain.Default().GetContract(item) + try: + hash = UInt160.ParseString(item).ToBytes() + except Exception: + print("Could not find contract from args: %s" % arguments) + return + + contract = Blockchain.Default().GetContract(hash) if contract is not None: contract.DetermineIsNEP5() @@ -336,6 +354,7 @@ def execute(self, arguments): return else: print("Please specify a contract") + return def command_desc(self): p1 = ParameterDesc('hash/all', 'the scripthash of the contract, or "all" shows all contracts') From 6696ff0da1835cef5535543a97102bdd3a5aa34a Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Sat, 8 Dec 2018 01:18:19 -0800 Subject: [PATCH 10/19] Update test_show_commands.py - add tests for updated Show.py --- .../Commands/tests/test_show_commands.py | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/neo/Prompt/Commands/tests/test_show_commands.py b/neo/Prompt/Commands/tests/test_show_commands.py index c3447beab..d4a58ddf1 100644 --- a/neo/Prompt/Commands/tests/test_show_commands.py +++ b/neo/Prompt/Commands/tests/test_show_commands.py @@ -175,6 +175,11 @@ def test_show_notifications(self): res = CommandShow().execute(args) self.assertFalse(res) + # test with no input + args = ['notifications'] + res = CommandShow().execute(args) + self.assertFalse(res) + # good test with address args = ['notifications', wallet_1_addr] res = CommandShow().execute(args) @@ -189,6 +194,32 @@ def test_show_notifications(self): res = CommandShow().execute(args) self.assertFalse(res) + # good test with contract + contract_hash = "31730cc9a1844891a3bafd1aa929a4142860d8d3" + args = ['notifications', contract_hash] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + jsn = res[0].ToJson() + self.assertEqual(jsn['notify_type'], 'transfer') + self.assertIn(contract_hash, jsn['contract']) + + # good test with contract 0x hash + contract_hash = "0x31730cc9a1844891a3bafd1aa929a4142860d8d3" + args = ['notifications', contract_hash] + res = CommandShow().execute(args) + self.assertTrue(res) + self.assertEqual(len(res), 1) + jsn = res[0].ToJson() + self.assertEqual(jsn['notify_type'], 'transfer') + self.assertEqual(contract_hash, jsn['contract']) + + # test contract not on the blockchain + contract_hash = "3a4acd3647086e7c44398aac0349802e6a171129" # NEX token hash + args = ['notifications', contract_hash] + res = CommandShow().execute(args) + self.assertFalse(res) + # good test with block index args = ['notifications', "12337"] res = CommandShow().execute(args) @@ -198,13 +229,18 @@ def test_show_notifications(self): self.assertEqual(jsn['notify_type'], 'transfer') self.assertEqual(jsn['block'], 12337) + # test block with no notifications + args = ['notifications', "1"] + res = CommandShow().execute(args) + self.assertFalse(res) + # test bad block index = Blockchain.Default().Height + 1 args = ['notifications', str(index)] res = CommandShow().execute(args) self.assertFalse(res) - # test invalid block input + # test invalid input args = ['notifications', "blah"] res = CommandShow().execute(args) self.assertFalse(res) @@ -306,6 +342,11 @@ def test_show_contract(self): self.assertEqual(res['token']['name'], "NEX Template V4") self.assertEqual(res['token']['symbol'], "NXT4") + # query with a contract scripthash not on the blockchain + args = ['contract', '3a4acd3647086e7c44398aac0349802e6a171129'] # NEX token hash + res = CommandShow().execute(args) + self.assertFalse(res) + # query bad input args = ['contract', 'blah'] res = CommandShow().execute(args) From d8303eed8c2304feaaf4d6cc54158009c33fb2a3 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Tue, 11 Dec 2018 23:54:03 -0800 Subject: [PATCH 11/19] Update Show.py - update per review --- neo/Prompt/Commands/Show.py | 44 +++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/neo/Prompt/Commands/Show.py b/neo/Prompt/Commands/Show.py index caf6091d4..9d0645859 100644 --- a/neo/Prompt/Commands/Show.py +++ b/neo/Prompt/Commands/Show.py @@ -76,11 +76,11 @@ def execute(self, arguments): print("Could not locate block %s" % item) return else: - print("please specify a block") + print("please specify a supported block attribute: index or scripthash") return def command_desc(self): - p1 = ParameterDesc('index/hash', 'the index or scripthash of the block') + p1 = ParameterDesc('attribute', 'the block index or scripthash') p2 = ParameterDesc('tx', 'arg to only show block transactions', optional=True) return CommandDesc('block', 'show a specified block', [p1, p2]) @@ -100,11 +100,11 @@ def execute(self, arguments): print("Could not locate header %s\n" % item) return else: - print("Please specify a header") + print("Please specify a supported header attribute: index or scripthash") return def command_desc(self): - p1 = ParameterDesc('index/hash', 'the index or scripthash of the block header') + p1 = ParameterDesc('attribute', 'the header index or scripthash') return CommandDesc('header', 'show the header of a specified block', [p1]) @@ -250,11 +250,11 @@ def execute(self, arguments): print("No events found for %s" % item) return else: - print("Please specify a block index, address, or contract hash") + print("Please specify a supported attribute: a block index, an address, or contract scripthash") return def command_desc(self): - p1 = ParameterDesc('block_index/address/contract_hash', 'the block, address, or contract to show notifications for') + p1 = ParameterDesc('attribute', 'the block index, an address, or contract scripthash to show notifications for') return CommandDesc('notifications', 'show specified contract execution notifications', [p1]) @@ -291,8 +291,13 @@ def execute(self, arguments): if item is not None: if item.lower() == "all": assets = Blockchain.Default().ShowAllAssets() - print("Assets: %s" % assets) - return assets + assetlist = [] + for asset in assets: + state = Blockchain.Default().GetAssetState(asset.decode('utf-8')).ToJson() + asset_dict = {state['name']: state['assetId']} + assetlist.append(asset_dict) + print(json.dumps(assetlist, indent=4)) + return assetlist if item.lower() == 'neo': assetId = Blockchain.Default().SystemShare().Hash @@ -314,14 +319,14 @@ def execute(self, arguments): print("Asset %s not found" % item) return else: - print("Please specify an asset hash or name") + print('Please specify a supported attribute: asset name, assetId, or "all" shows all assets') return def command_desc(self): - p1 = ParameterDesc('name/assetId/all', 'the name or assetId of the asset, or "all" shows all assets\n\n') - f"{' ':>17} Example:\n" - f"{' ':>20} 'neo' or 'c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b'\n" - f"{' ':>20} 'gas' or '602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7'\n" + p1 = ParameterDesc('attribute', 'the asset name, assetId, or "all" shows all assets\n\n' + f"{' ':>17} Example:\n" + f"{' ':>20} 'neo' or 'c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b'\n" + f"{' ':>20} 'gas' or '602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7'\n") return CommandDesc('asset', 'show a specified asset', [p1]) @@ -334,8 +339,13 @@ def execute(self, arguments): if item is not None: if item.lower() == "all": contracts = Blockchain.Default().ShowAllContracts() - print("Contracts: %s" % contracts) - return contracts + contractlist = [] + for contract in contracts: + state = Blockchain.Default().GetContract(contract.decode('utf-8')).ToJson() + contract_dict = {state['name']: state['code']['hash']} + contractlist.append(contract_dict) + print(json.dumps(contractlist, indent=4)) + return contractlist try: hash = UInt160.ParseString(item).ToBytes() @@ -353,9 +363,9 @@ def execute(self, arguments): print("Contract %s not found" % item) return else: - print("Please specify a contract") + print('Please specify a supported attribute: contract scripthash or "all"') return def command_desc(self): - p1 = ParameterDesc('hash/all', 'the scripthash of the contract, or "all" shows all contracts') + p1 = ParameterDesc('attribute', 'the contract scripthash, or "all" shows all contracts') return CommandDesc('contract', 'show a specified smart contract', [p1]) From bbf2b18009d98225ff461a56b79e787ad6214421 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Tue, 11 Dec 2018 23:54:52 -0800 Subject: [PATCH 12/19] Update test_show_commands.py - update tests to match review updates --- neo/Prompt/Commands/tests/test_show_commands.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/neo/Prompt/Commands/tests/test_show_commands.py b/neo/Prompt/Commands/tests/test_show_commands.py index d4a58ddf1..942168bdd 100644 --- a/neo/Prompt/Commands/tests/test_show_commands.py +++ b/neo/Prompt/Commands/tests/test_show_commands.py @@ -287,8 +287,9 @@ def test_show_asset(self): args = ['asset', 'all'] res = CommandShow().execute(args) self.assertTrue(res) - self.assertIn("602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7", str(res)) - self.assertIn("c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", str(res)) + self.assertEqual(len(res), 2) + self.assertEqual(res[1]['NEO'], "0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b") + self.assertEqual(res[0]['NEOGas'], "0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7") # query with "neo" args = ['asset', 'neo'] @@ -331,8 +332,8 @@ def test_show_contract(self): args = ['contract', 'all'] res = CommandShow().execute(args) self.assertTrue(res) - res = list(res) self.assertEqual(len(res), 6) + self.assertEqual(res[0]["test NEX Template V4"], '0x31730cc9a1844891a3bafd1aa929a4142860d8d3') # query with contract scripthash args = ['contract', '31730cc9a1844891a3bafd1aa929a4142860d8d3'] From 10dc2b1295edd46b8deb3566d12d0e262815b9ab Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:20:25 -0800 Subject: [PATCH 13/19] Update Show.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/Prompt/Commands/Show.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Prompt/Commands/Show.py b/neo/Prompt/Commands/Show.py index 9d0645859..50a088af5 100644 --- a/neo/Prompt/Commands/Show.py +++ b/neo/Prompt/Commands/Show.py @@ -342,7 +342,7 @@ def execute(self, arguments): contractlist = [] for contract in contracts: state = Blockchain.Default().GetContract(contract.decode('utf-8')).ToJson() - contract_dict = {state['name']: state['code']['hash']} + contract_dict = {state['name']: state['hash']} contractlist.append(contract_dict) print(json.dumps(contractlist, indent=4)) return contractlist From 7fcd60082bc36cd52519e6315329824ccbed4c94 Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:21:11 -0800 Subject: [PATCH 14/19] Update FunctionCode.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/Core/FunctionCode.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/neo/Core/FunctionCode.py b/neo/Core/FunctionCode.py index 4e9c20c85..f54b3c13f 100644 --- a/neo/Core/FunctionCode.py +++ b/neo/Core/FunctionCode.py @@ -1,7 +1,7 @@ from neocore.IO.Mixins import SerializableMixin from neocore.Cryptography.Crypto import Crypto from neocore.BigInteger import BigInteger -from neo.SmartContract.ContractParameterType import ContractParameterType +from neo.SmartContract.ContractParameterType import ContractParameterType, ToName class FunctionCode(SerializableMixin): @@ -104,9 +104,11 @@ def ToJson(self): Returns: dict: """ + parameters = self.ParameterList.hex() + paramlist = [ToName(ContractParameterType.FromString(parameters[i:i + 2]).value) for i in range(0, len(parameters), 2)] return { 'hash': self.ScriptHash().To0xString(), 'script': self.Script.hex(), - 'parameters': self.ParameterList.hex(), - 'returntype': self.ReturnType if type(self.ReturnType) is int else self.ReturnType.hex() + 'parameters': paramlist, + 'returntype': ToName(self.ReturnType) if type(self.ReturnType) is int else ToName(int(self.ReturnType)) } From 4fbebf99d9e805d869b8e1d40bc718b0c7b1b3aa Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:22:38 -0800 Subject: [PATCH 15/19] Update ContractState.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/Core/State/ContractState.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/neo/Core/State/ContractState.py b/neo/Core/State/ContractState.py index a26863d7c..7eb121ecf 100644 --- a/neo/Core/State/ContractState.py +++ b/neo/Core/State/ContractState.py @@ -183,8 +183,6 @@ def ToJson(self): Returns: dict: """ - codejson = self.Code.ToJson() - name = 'Contract' try: @@ -192,10 +190,11 @@ def ToJson(self): except Exception as e: pass - jsn = { + jsn = {'version': self.StateVersion} + + jsn_code = self.Code.ToJson() - 'version': self.StateVersion, - 'code': codejson, + jsn_contract = { 'name': name, 'code_version': self.CodeVersion.decode('utf-8'), 'author': self.Author.decode('utf-8'), @@ -208,6 +207,9 @@ def ToJson(self): } } + jsn.update(jsn_code) + jsn.update(jsn_contract) + if self._nep_token: jsn['token'] = self._nep_token.ToJson() From 1f8ab44e6140c9ddac3f54262a3ef157ad5488df Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:23:17 -0800 Subject: [PATCH 16/19] Update test_transactions.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/Core/TX/test_transactions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo/Core/TX/test_transactions.py b/neo/Core/TX/test_transactions.py index e6fa11c92..bba35c819 100644 --- a/neo/Core/TX/test_transactions.py +++ b/neo/Core/TX/test_transactions.py @@ -90,8 +90,8 @@ def test_publish_tx_deserialize(self): self.assertEqual(contract['description'], 'Lock your assets until a timestamp.') self.assertEqual(contract['code']['hash'], '0xffbd1a7ad1e2348b6b3822426f364bfb4bcce3b9') - self.assertEqual(contract['code']['returntype'], 1) - self.assertEqual(contract['code']['parameters'], '020500') + self.assertEqual(contract['code']['returntype'], "Boolean") + self.assertEqual(contract['code']['parameters'], ['Integer', 'ByteArray', 'Signature']) self.assertEqual(Fixed8.FromDecimal(settings.ALL_FEES['PublishTransaction']), tx.SystemFee()) ir = b'd100644011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111081234567890abcdef0415cd5b0769cc4ee2f1c9f4e0782756dabf246d0a4fe60a035400000000' From 7cbdb94a9e8c9e18ef63ff092e7004e60782e35e Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:24:31 -0800 Subject: [PATCH 17/19] Update ContractParameterType.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/SmartContract/ContractParameterType.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/SmartContract/ContractParameterType.py b/neo/SmartContract/ContractParameterType.py index 470979b16..25b876653 100755 --- a/neo/SmartContract/ContractParameterType.py +++ b/neo/SmartContract/ContractParameterType.py @@ -96,7 +96,7 @@ def ToName(param_type): for item in items: name = item[0] - val = int(item[1]) + val = int(item[1].value) if val == param_type: return name From 03c4c0aa392afbe9bc360a0d1fe5850c2607325f Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:25:08 -0800 Subject: [PATCH 18/19] Update SmartContractEvent.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/SmartContract/SmartContractEvent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/SmartContract/SmartContractEvent.py b/neo/SmartContract/SmartContractEvent.py index 7e027ca37..e484dc47e 100644 --- a/neo/SmartContract/SmartContractEvent.py +++ b/neo/SmartContract/SmartContractEvent.py @@ -161,7 +161,7 @@ def ToJson(self): if self.event_type in [SmartContractEvent.CONTRACT_CREATED, SmartContractEvent.CONTRACT_MIGRATED]: jsn['contract'] = self.contract.ToJson() - del jsn['contract']['code']['script'] + del jsn['contract']['script'] if self.token: jsn['token'] = self.token.ToJson() From 594074c8ee5b2511e10dca5ce4d895760674338b Mon Sep 17 00:00:00 2001 From: jseagrave21 <40873301+jseagrave21@users.noreply.github.com> Date: Wed, 12 Dec 2018 11:37:46 -0800 Subject: [PATCH 19/19] Update test_json_rpc_api.py - update for https://github.com/CityOfZion/neo-python/pull/750 --- neo/api/JSONRPC/test_json_rpc_api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/neo/api/JSONRPC/test_json_rpc_api.py b/neo/api/JSONRPC/test_json_rpc_api.py index b016035af..6af137f4a 100644 --- a/neo/api/JSONRPC/test_json_rpc_api.py +++ b/neo/api/JSONRPC/test_json_rpc_api.py @@ -255,9 +255,9 @@ def test_get_contract_state(self): res = json.loads(self.app.home(mock_req)) self.assertEqual(res['result']['code_version'], '') self.assertEqual(res['result']['properties']['storage'], True) - self.assertEqual(res['result']['code']['hash'], '0xb9fbcff6e50fd381160b822207231233dd3c56c2') - self.assertEqual(res['result']['code']['returntype'], 5) - self.assertEqual(res['result']['code']['parameters'], '0710') + self.assertEqual(res['result']['hash'], '0xb9fbcff6e50fd381160b822207231233dd3c56c2') + self.assertEqual(res['result']['returntype'], "ByteArray") + self.assertEqual(res['result']['parameters'], ["String", "Array"]) def test_get_contract_state_0x(self): contract_hash = "0xb9fbcff6e50fd381160b822207231233dd3c56c2"