Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Improve parameter parsing [02] #973

Open
wants to merge 17 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions neo/Prompt/Commands/BuildNRun.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
44 changes: 35 additions & 9 deletions neo/Prompt/Commands/Invoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -161,19 +162,17 @@ 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])

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 = []
Expand All @@ -183,6 +182,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:
params.reverse()

sb = ScriptBuilder()

Expand Down Expand Up @@ -363,7 +377,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()
Expand Down Expand Up @@ -444,16 +458,28 @@ 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()
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:
invoke_args.reverse()

sb = ScriptBuilder()
Expand Down
3 changes: 2 additions & 1 deletion neo/Prompt/Commands/SC.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
16 changes: 16 additions & 0 deletions neo/Prompt/Commands/tests/test_sc_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -379,6 +388,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]):
Expand Down
57 changes: 30 additions & 27 deletions neo/Prompt/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down
8 changes: 4 additions & 4 deletions neo/SmartContract/tests/test_gas_costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand All @@ -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)
Expand Down Expand Up @@ -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)
self.assertEqual(expected_cost, engine.GasConsumed())
self.assertEqual(tx.Gas, expected_gas)

Expand Down