From 528fb1e80d3858b55c2abc1c8e03d25d67abdc9e Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Fri, 28 Jun 2019 01:55:30 -0400 Subject: [PATCH 01/12] impliment parameter verification function - verifies parameters input via command line and --i flag - ensures parameter input is identical --- neo/Prompt/Commands/Invoke.py | 26 ++++++++++++---- neo/Prompt/Utils.py | 57 ++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index dd0cf32de..7f5d45599 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -24,6 +24,7 @@ from neo.SmartContract import TriggerType from neo.SmartContract.StateMachine import StateMachine from neo.SmartContract.ContractParameterContext import ContractParametersContext +from neo.SmartContract.ContractParameter import ContractParameterType from neo.SmartContract.Contract import Contract from neo.Core.Cryptography.Helper import scripthash_to_address from neo.Core.Cryptography.Crypto import Crypto @@ -170,12 +171,10 @@ def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, contract = BC.GetContract(args[0]) if contract: - # params = args[1:] if len(args) > 1 else [] params, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments(params) params, parse_addresses = PromptUtils.get_parse_addresses(params) - params.reverse() if '--i' in params: params = [] @@ -185,6 +184,15 @@ def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, return None, None, None, None, False params.append(param) params.reverse() + else: + i_args = [] + for index, iarg in enumerate(contract.Code.ParameterList): + param, abort = PromptUtils.verify_params(ContractParameterType(iarg), params[index]) + if abort: + return None, None, None, None, False + i_args.append(param) + i_args.reverse() + params = i_args sb = ScriptBuilder() @@ -468,17 +476,23 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, invoke_args, neo_to_attach, gas_to_attach = PromptUtils.get_asset_attachments(invoke_args) invoke_args, no_parse_addresses = PromptUtils.get_parse_addresses(invoke_args) - invoke_args.reverse() - if '--i' in invoke_args: invoke_args = [] for index, iarg in enumerate(contract_state.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, [], 0, None - else: - invoke_args.append(param) + invoke_args.append(param) invoke_args.reverse() + else: + i_args = [] + for index, iarg in enumerate(contract_state.Code.ParameterList): + param, abort = PromptUtils.verify_params(ContractParameterType(iarg), invoke_args[index]) + if abort: + return None, [], 0, None + i_args.append(param) + i_args.reverse() + invoke_args = i_args sb = ScriptBuilder() diff --git a/neo/Prompt/Utils.py b/neo/Prompt/Utils.py index 336ac9b7d..17e311704 100644 --- a/neo/Prompt/Utils.py +++ b/neo/Prompt/Utils.py @@ -307,6 +307,35 @@ def get_input_prompt(message): return prompt(message) +def verify_params(ptype, param): + if ptype == ContractParameterType.String: + return str(param), False + elif ptype == ContractParameterType.Integer: + return int(param), False + elif ptype == ContractParameterType.Boolean: + return bool(param), False + elif ptype == ContractParameterType.PublicKey: + try: + return ECDSA.decode_secp256r1(param).G, False + except ValueError: + return None, True + elif ptype == ContractParameterType.ByteArray: + if isinstance(param, str) and len(param) == 34 and param[0] == 'A': + return Helper.AddrStrToScriptHash(param).Data, False + res = eval(param, {"__builtins__": {'bytearray': bytearray, 'bytes': bytes}}, {}) + if isinstance(res, bytes): + return bytearray(res), False + return res, False + + elif ptype == ContractParameterType.Array: + res = eval(param) + if isinstance(res, list): + return res, False + raise Exception("Please provide a list") + else: + raise Exception("Unknown param type %s " % ptype.name) + + def gather_param(index, param_type, do_continue=True): ptype = ContractParameterType(param_type) prompt_message = '[Param %s] %s input: ' % (index, ptype.name) @@ -322,33 +351,7 @@ def gather_param(index, param_type, do_continue=True): return None, True try: - - if ptype == ContractParameterType.String: - return str(result), False - elif ptype == ContractParameterType.Integer: - return int(result), False - elif ptype == ContractParameterType.Boolean: - return bool(result), False - elif ptype == ContractParameterType.PublicKey: - try: - return ECDSA.decode_secp256r1(result).G, False - except ValueError: - return None, True - elif ptype == ContractParameterType.ByteArray: - if isinstance(result, str) and len(result) == 34 and result[0] == 'A': - return Helper.AddrStrToScriptHash(result).Data, False - res = eval(result, {"__builtins__": {'bytearray': bytearray, 'bytes': bytes}}, {}) - if isinstance(res, bytes): - return bytearray(res), False - return res, False - - elif ptype == ContractParameterType.Array: - res = eval(result) - if isinstance(res, list): - return res, False - raise Exception("Please provide a list") - else: - raise Exception("Unknown param type %s " % ptype.name) + return verify_params(ptype, result) except KeyboardInterrupt: # Control-C pressed: exit From 485904e9204dd958a86bdde7e8ab8da15b2ff01b Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Fri, 28 Jun 2019 21:39:30 -0400 Subject: [PATCH 02/12] implement user_entry flag to ensure existing logic is not disrupted --- neo/Prompt/Commands/BuildNRun.py | 7 ++-- neo/Prompt/Commands/Invoke.py | 55 ++++++++++++++++++++------------ neo/Prompt/Commands/SC.py | 3 +- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/neo/Prompt/Commands/BuildNRun.py b/neo/Prompt/Commands/BuildNRun.py index 5b6f5f73e..b374b4f41 100644 --- a/neo/Prompt/Commands/BuildNRun.py +++ b/neo/Prompt/Commands/BuildNRun.py @@ -90,9 +90,10 @@ def DoRun(contract_script, arguments, wallet, path, verbose=True, except Exception: raise TypeError - tx, result, total_ops, engine = test_deploy_and_invoke(script, i_args, wallet, from_addr, - min_fee, invocation_test_mode, debug_map=debug_map, - invoke_attrs=invoke_attrs, owners=owners, enable_debugger=enable_debugger) + tx, result, total_ops, engine = test_deploy_and_invoke(script, i_args, wallet, from_addr, min_fee, + invocation_test_mode, debug_map=debug_map, + invoke_attrs=invoke_attrs, owners=owners, + enable_debugger=enable_debugger, user_entry=True) i_args.reverse() return_type_results = [] diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 7f5d45599..3c64fe292 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -164,8 +164,8 @@ def InvokeWithTokenVerificationScript(wallet, tx, token, fee=Fixed8.Zero(), invo return False -def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, - min_fee=DEFAULT_MIN_FEE, invoke_attrs=None, owners=None): +def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE, + invoke_attrs=None, owners=None, user_entry=False): BC = GetBlockchain() contract = BC.GetContract(args[0]) @@ -184,15 +184,21 @@ def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, return None, None, None, None, False params.append(param) params.reverse() + elif user_entry: + try: + i_args = [] + for index, iarg in enumerate(contract.Code.ParameterList): + param, abort = PromptUtils.verify_params(ContractParameterType(iarg), params[index]) + if abort: + return None, None, None, None, False + i_args.append(param) + i_args.reverse() + params = i_args + except IndexError: + print(f"Check params. {len(contract.Code.ParameterList)} params specified and only {len(params)} given.") + return None, None, None, None, False else: - i_args = [] - for index, iarg in enumerate(contract.Code.ParameterList): - param, abort = PromptUtils.verify_params(ContractParameterType(iarg), params[index]) - if abort: - return None, None, None, None, False - i_args.append(param) - i_args.reverse() - params = i_args + params.reverse() sb = ScriptBuilder() @@ -393,9 +399,10 @@ def test_invoke(script, wallet, outputs, withdrawal_tx=None, return None, None, None, None, False -def test_deploy_and_invoke(deploy_script, invoke_args, wallet, - from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, - debug_map=None, invoke_attrs=None, owners=None, enable_debugger=False): +def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, + min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, + debug_map=None, invoke_attrs=None, owners=None, + enable_debugger=False, user_entry=False): bc = GetBlockchain() accounts = DBInterface(bc._db, DBPrefix.ST_Account, AccountState) @@ -484,15 +491,21 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, return None, [], 0, None invoke_args.append(param) invoke_args.reverse() + elif user_entry: + try: + i_args = [] + for index, iarg in enumerate(contract_state.Code.ParameterList): + param, abort = PromptUtils.verify_params(ContractParameterType(iarg), invoke_args[index]) + if abort: + return None, [], 0, None + i_args.append(param) + i_args.reverse() + invoke_args = i_args + except IndexError: + print(f"Check params. {len(contract_state.Code.ParameterList)} params specified and only {len(invoke_args)} given.") + return None, [], 0, None else: - i_args = [] - for index, iarg in enumerate(contract_state.Code.ParameterList): - param, abort = PromptUtils.verify_params(ContractParameterType(iarg), invoke_args[index]) - if abort: - return None, [], 0, None - i_args.append(param) - i_args.reverse() - invoke_args = i_args + invoke_args.reverse() sb = ScriptBuilder() diff --git a/neo/Prompt/Commands/SC.py b/neo/Prompt/Commands/SC.py index aa6ec77d6..bf86f2780 100644 --- a/neo/Prompt/Commands/SC.py +++ b/neo/Prompt/Commands/SC.py @@ -185,7 +185,8 @@ def execute(self, arguments): logger.debug("invalid fee") return False - tx, fee, results, num_ops, engine_success = TestInvokeContract(wallet, arguments, from_addr=from_addr, invoke_attrs=invoke_attrs, owners=owners) + tx, fee, results, num_ops, engine_success = TestInvokeContract(wallet, arguments, from_addr=from_addr, invoke_attrs=invoke_attrs, + owners=owners, user_entry=True) if tx is not None and results is not None: if return_type is not None: From 0f1e24225cb420dfc1fb647991c8ad4e48865400 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Fri, 28 Jun 2019 21:40:12 -0400 Subject: [PATCH 03/12] add tests for too few params entered --- neo/Prompt/Commands/tests/test_sc_commands.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/neo/Prompt/Commands/tests/test_sc_commands.py b/neo/Prompt/Commands/tests/test_sc_commands.py index b33da8b09..49e4d5755 100644 --- a/neo/Prompt/Commands/tests/test_sc_commands.py +++ b/neo/Prompt/Commands/tests/test_sc_commands.py @@ -128,6 +128,15 @@ def test_sc_buildrun(self): self.assertFalse(tx) self.assertIn("run `sc build_run help` to see supported queries", mock_print.getvalue()) + # test too few args + PromptData.Wallet = self.GetWallet1(recreate=True) + with patch('sys.stdout', new=StringIO()) as mock_print: + args = ['build_run', 'neo/Prompt/Commands/tests/SampleSC.py', 'True', 'False', 'False', '070502', '02', 'add', 'AG4GfwjnvydAZodm4xEDivguCtjCFzLcJy', + ] # missing third param + tx, result, total_ops, engine = CommandSC().execute(args) + self.assertFalse(tx) + self.assertIn("Check params. 3 params specified and only 2 given.", mock_print.getvalue()) + # test successful build and run PromptData.Wallet = self.GetWallet1(recreate=True) with patch('sys.stdout', new=StringIO()) as mock_print: @@ -402,6 +411,13 @@ def test_sc_invoke(self): self.assertFalse(res) self.assertIn("Error testing contract invoke", mock_print.getvalue()) + # test too few args + with patch('sys.stdout', new=StringIO()) as mock_print: + args = ['invoke', token_hash_str, 'name'] # missing second arg + res = CommandSC().execute(args) + self.assertFalse(res) + self.assertIn("Check params. 2 params specified and only 1 given.", mock_print.getvalue()) + # test with keyboard interrupt with patch('sys.stdout', new=StringIO()) as mock_print: with patch('neo.Prompt.Commands.SC.prompt', side_effect=[KeyboardInterrupt]): From 10570bae35c701e16cc502b8440b39346b8d1804 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Fri, 28 Jun 2019 21:46:13 -0400 Subject: [PATCH 04/12] updated CHANGELOG.rst --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d221b77e3..3c54c5544 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -47,6 +47,7 @@ All notable changes to this project are documented in this file. - Add workaround for ``Neo.Contract.Create`` SYSCALl accepting invalid ``ContractParameterType``'s until neo-cli fixes it to keep same state - Fix parsing nested lists `#954 `_ - Fix clearing storage manipulations on failed invocation transaction execution +- Fix param parsing input from command line [0.8.4] 2019-02-14 From efb6ef47887237822d8ad1c844b3a794255bcece Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Fri, 28 Jun 2019 22:09:26 -0400 Subject: [PATCH 05/12] update tests --- neo/SmartContract/tests/test_gas_costs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/neo/SmartContract/tests/test_gas_costs.py b/neo/SmartContract/tests/test_gas_costs.py index 5019b4046..c17750091 100644 --- a/neo/SmartContract/tests/test_gas_costs.py +++ b/neo/SmartContract/tests/test_gas_costs.py @@ -82,7 +82,7 @@ def test_build_contract_3(self): expected_fee = Fixed8.FromDecimal(.0001) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_fee) - self.assertEqual(result[0].GetByteArray(), bytearray(b'\xab\xab\xab\xab\xab\xab')) + self.assertEqual(result[0].GetByteArray(), bytearray(b'abababababab')) def test_build_contract_4(self): """ @@ -98,7 +98,7 @@ def test_build_contract_4(self): tx, result, total_ops, engine = BuildAndRun(arguments, wallet, False) - expected_cost = Fixed8.FromDecimal(2.153) + expected_cost = Fixed8.FromDecimal(3.153) expected_fee = Fixed8.FromDecimal(.0001) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_fee) @@ -126,8 +126,8 @@ def test_build_contract_5(self): tx, result, total_ops, engine = BuildAndRun(arguments, wallet, False) - expected_cost = Fixed8(1046600000) - expected_gas = Fixed8.FromDecimal(1.0) + expected_cost = Fixed8.FromDecimal(15.466) + expected_gas = Fixed8.FromDecimal(6.0) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_gas) From 98c8863daf6b63b93bee48eb3e150554eb9904a0 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Tue, 2 Jul 2019 22:48:39 -0400 Subject: [PATCH 06/12] remove Ceiling rounding for invocation GAS costs - based on discussion from @hal0x2328 and @ixje in Slack - adding to PR #973 because the change is so small --- neo/Prompt/Commands/Invoke.py | 2 -- neo/SmartContract/tests/test_gas_costs.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 3c64fe292..e24c97f61 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -359,7 +359,6 @@ def test_invoke(script, wallet, outputs, withdrawal_tx=None, # print("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) - consumed = consumed.Ceil() net_fee = None tx_gas = None @@ -604,7 +603,6 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) - consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee diff --git a/neo/SmartContract/tests/test_gas_costs.py b/neo/SmartContract/tests/test_gas_costs.py index c17750091..7384770a9 100644 --- a/neo/SmartContract/tests/test_gas_costs.py +++ b/neo/SmartContract/tests/test_gas_costs.py @@ -127,7 +127,7 @@ def test_build_contract_5(self): tx, result, total_ops, engine = BuildAndRun(arguments, wallet, False) expected_cost = Fixed8.FromDecimal(15.466) - expected_gas = Fixed8.FromDecimal(6.0) + expected_gas = Fixed8.FromDecimal(5.466) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_gas) From 29e7fc4b9d9f9a4036bf54c7bcc33598ef7dc5e3 Mon Sep 17 00:00:00 2001 From: Erik van den Brink Date: Wed, 3 Jul 2019 09:56:23 +0200 Subject: [PATCH 07/12] restore user_entry flag --- neo/Prompt/Commands/Invoke.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 3855af574..31f0591a5 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -385,7 +385,7 @@ def test_invoke(script, wallet, outputs, withdrawal_tx=None, def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, - debug_map=None, invoke_attrs=None, owners=None, enable_debugger=False, snapshot=None): + debug_map=None, invoke_attrs=None, owners=None, enable_debugger=False, snapshot=None, user_entry=False): if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() From 4d32219831c00533fcb85ca78ec50b665d374381 Mon Sep 17 00:00:00 2001 From: Erik van den Brink Date: Wed, 3 Jul 2019 10:06:27 +0200 Subject: [PATCH 08/12] fix lint error --- neo/Prompt/Commands/Invoke.py | 1 + 1 file changed, 1 insertion(+) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 31f0591a5..4b910bb14 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -383,6 +383,7 @@ def test_invoke(script, wallet, outputs, withdrawal_tx=None, return None, None, None, None, False + def test_deploy_and_invoke(deploy_script, invoke_args, wallet, from_addr=None, min_fee=DEFAULT_MIN_FEE, invocation_test_mode=True, debug_map=None, invoke_attrs=None, owners=None, enable_debugger=False, snapshot=None, user_entry=False): From 9611d835abf6eb4dfd172026233e8bcfaf70ae94 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Mon, 9 Sep 2019 22:22:49 -0700 Subject: [PATCH 09/12] update Changelog for 0.9.1-dev --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 20c499762..a38532dbd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ All notable changes to this project are documented in this file. - Fix network syncing against neo-cli ``2.10.3`` clients - Update Python requirements - Fix Docker configuration pip issue +- Fix param parsing input from command line [0.9.0] 2019-08-21 @@ -55,7 +56,6 @@ All notable changes to this project are documented in this file. - Add workaround for ``Neo.Contract.Create`` SYSCALl accepting invalid ``ContractParameterType``'s until neo-cli fixes it to keep same state - Fix parsing nested lists `#954 `_ - Fix clearing storage manipulations on failed invocation transaction execution -- Fix param parsing input from command line - Port caching layer from neo-cli - Fix ``Contract_Migrate`` syscall - Fix ``BigInteger`` modulo for negative divisor values From 016f30d658aafcc3a58d3b63432cbfca568a21ca Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Tue, 10 Sep 2019 01:00:04 -0700 Subject: [PATCH 10/12] revert removal of `Ceil()` function based on https://github.com/CityOfZion/neo-python/pull/973#pullrequestreview-271267455 --- neo/Prompt/Commands/Invoke.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 63539b69e..77863f4aa 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -343,6 +343,7 @@ def test_invoke(script, wallet, outputs, withdrawal_tx=None, # print("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) + consumed = consumed.Ceil() net_fee = None tx_gas = None @@ -572,6 +573,7 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) + consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee From 22a33391302323c193b1258b880d6c8d40e48896 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Tue, 10 Sep 2019 01:06:24 -0700 Subject: [PATCH 11/12] update unittest - update test_gas_costs.py based on using the `Ceil()` function --- neo/SmartContract/tests/test_gas_costs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/SmartContract/tests/test_gas_costs.py b/neo/SmartContract/tests/test_gas_costs.py index 7384770a9..106d7b150 100644 --- a/neo/SmartContract/tests/test_gas_costs.py +++ b/neo/SmartContract/tests/test_gas_costs.py @@ -127,7 +127,7 @@ def test_build_contract_5(self): tx, result, total_ops, engine = BuildAndRun(arguments, wallet, False) expected_cost = Fixed8.FromDecimal(15.466) - expected_gas = Fixed8.FromDecimal(5.466) + expected_gas = Fixed8.FromDecimal(6) self.assertEqual(expected_cost, engine.GasConsumed()) self.assertEqual(tx.Gas, expected_gas) From d27975ee433ba05ddeb562363ce3be32504f5ed8 Mon Sep 17 00:00:00 2001 From: jseagrave21 Date: Thu, 12 Sep 2019 00:33:34 -0700 Subject: [PATCH 12/12] improve per https://github.com/CityOfZion/neo-python/pull/973#pullrequestreview-286132074 --- neo/Prompt/Commands/Invoke.py | 12 ++++++++++-- neo/Prompt/Utils.py | 22 ++++++++++++++-------- neo/Prompt/test_utils.py | 12 ++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/neo/Prompt/Commands/Invoke.py b/neo/Prompt/Commands/Invoke.py index 77863f4aa..6beeaff8f 100644 --- a/neo/Prompt/Commands/Invoke.py +++ b/neo/Prompt/Commands/Invoke.py @@ -186,7 +186,8 @@ def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, min_fee try: i_args = [] for index, iarg in enumerate(contract.Code.ParameterList): - param, abort = PromptUtils.verify_params(ContractParameterType(iarg), params[index]) + ptype = ContractParameterType(iarg) + param, abort = PromptUtils.verify_params(ptype, params[index]) if abort: return None, None, None, None, False i_args.append(param) @@ -195,6 +196,9 @@ def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, min_fee except IndexError: print(f"Check params. {len(contract.Code.ParameterList)} params specified and only {len(params)} given.") return None, None, None, None, False + except Exception as e: + print("Could not parse param as %s : %s " % (ptype, e)) + return None, None, None, None, False else: params.reverse() @@ -470,7 +474,8 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, try: i_args = [] for index, iarg in enumerate(contract_state.Code.ParameterList): - param, abort = PromptUtils.verify_params(ContractParameterType(iarg), invoke_args[index]) + ptype = ContractParameterType(iarg) + param, abort = PromptUtils.verify_params(ptype, invoke_args[index]) if abort: return None, [], 0, None i_args.append(param) @@ -479,6 +484,9 @@ def test_deploy_and_invoke(deploy_script, invoke_args, wallet, except IndexError: print(f"Check params. {len(contract_state.Code.ParameterList)} params specified and only {len(invoke_args)} given.") return None, [], 0, None + except Exception as e: + print("Could not parse param as %s : %s " % (ptype, e)) + return None, [], 0, None else: invoke_args.reverse() diff --git a/neo/Prompt/Utils.py b/neo/Prompt/Utils.py index 17e311704..2b93d7779 100644 --- a/neo/Prompt/Utils.py +++ b/neo/Prompt/Utils.py @@ -322,15 +322,21 @@ def verify_params(ptype, param): elif ptype == ContractParameterType.ByteArray: if isinstance(param, str) and len(param) == 34 and param[0] == 'A': return Helper.AddrStrToScriptHash(param).Data, False - res = eval(param, {"__builtins__": {'bytearray': bytearray, 'bytes': bytes}}, {}) - if isinstance(res, bytes): - return bytearray(res), False - return res, False + try: + res = eval(param, {"__builtins__": {'bytearray': bytearray, 'bytes': bytes}}, {}) + if isinstance(res, bytes): + return bytearray(res), False + return res, False + except Exception: + raise Exception("Please provide a bytearray or bytes object") elif ptype == ContractParameterType.Array: - res = eval(param) - if isinstance(res, list): - return res, False + try: + res = eval(param) + if isinstance(res, list): + return res, False + except Exception: + pass raise Exception("Please provide a list") else: raise Exception("Unknown param type %s " % ptype.name) @@ -343,7 +349,7 @@ def gather_param(index, param_type, do_continue=True): try: result = get_input_prompt(prompt_message) except KeyboardInterrupt: - print("Input cancelled") + print("Input cancelled") return None, True except Exception as e: print(str(e)) diff --git a/neo/Prompt/test_utils.py b/neo/Prompt/test_utils.py index 9241c8817..9bd389a0b 100644 --- a/neo/Prompt/test_utils.py +++ b/neo/Prompt/test_utils.py @@ -153,11 +153,13 @@ def test_parse_no_address(self): self.assertFalse(result) def test_gather_param(self): + # test string input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='hello') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.String) self.assertEqual(result, 'hello') + # test integer input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) @@ -173,6 +175,7 @@ def test_gather_param(self): self.assertEqual(result, 1) + # test bytearray input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="bytearray(b'abc')") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) @@ -183,6 +186,14 @@ def test_gather_param(self): self.assertEqual(result, bytearray(b'abc')) + # test string input when expecting bytearray + with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="abc") as fake_prompt: + result, abort = Utils.gather_param(0, ContractParameterType.ByteArray, do_continue=False) + + self.assertEqual(result, None) + self.assertEqual(abort, True) + + # test boolean input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="abc") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) @@ -199,6 +210,7 @@ def test_gather_param(self): self.assertEqual(result, bytearray(b'\xf9\x1dkp\x85\xdb|Z\xaf\t\xf1\x9e\xee\xc1\xca<\r\xb2\xc6\xec')) + # test array input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c"]') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array)