def TestInvokeContract(wallet, args, withdrawal_tx=None, from_addr=None, min_fee=DEFAULT_MIN_FEE, invoke_attrs=None, owners=None): 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 = [] for index, iarg in enumerate(contract.Code.ParameterList): param, abort = PromptUtils.gather_param(index, iarg) if abort: return None, None, None, None, False params.append(param) params.reverse() sb = ScriptBuilder() for p in params: process_params(sb, p, wallet, parse_addresses) sb.EmitAppCall(contract.Code.ScriptHash().Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract.Code.ScriptHash()) outputs.append(output) return test_invoke(out, wallet, outputs, withdrawal_tx, from_addr, min_fee, invoke_attrs=invoke_attrs, owners=owners) else: print("Contract %s not found" % args[0]) return None, None, None, None, False
def test_gather_param(self): 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') with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='1') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1.03) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) 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) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="b'abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, True) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=0) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, False) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=0) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, False) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='AeV59NyZtgj5AMQ7vY6yhr2MRvcfFeLWSb') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual(result, bytearray(b'\xf9\x1dkp\x85\xdb|Z\xaf\t\xf1\x9e\xee\xc1\xca<\r\xb2\xc6\xec')) 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) self.assertEqual(result, ['a', 'b', 'c']) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"]') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array) self.assertEqual(result, ['a', 'b', 'c', [1, 3, 4], 'e']) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array, do_continue=False) self.assertEqual(result, 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): bc = GetBlockchain() accounts = DBCollection(bc._db, DBPrefix.ST_Account, AccountState) assets = DBCollection(bc._db, DBPrefix.ST_Asset, AssetState) validators = DBCollection(bc._db, DBPrefix.ST_Validator, ValidatorState) contracts = DBCollection(bc._db, DBPrefix.ST_Contract, ContractState) storages = DBCollection(bc._db, DBPrefix.ST_Storage, StorageItem) if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBCollection(debug_storage.db, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) except (ValueError, TXFeeError): pass context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() script_table = CachedScriptTable(contracts) service = StateMachine(accounts, validators, assets, contracts, storages, None) contract = wallet.GetDefaultContract() dtx.Attributes = [ TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False)) ] dtx.Attributes = make_unique_script_attr(dtx.Attributes) to_dispatch = [] engine = ApplicationEngine(trigger_type=TriggerType.Application, container=dtx, table=script_table, service=service, gas=dtx.Gas, testMode=True) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke d_success = engine.Execute() if d_success: items = engine.ResultStack.Items contract_state = None for i in items: if type(i) is ContractState: contract_state = i break elif type(i) is InteropInterface: item = i.GetInterface() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() 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.reverse() sb = ScriptBuilder() for p in invoke_args: item = PromptUtils.parse_param(p, wallet, parse_addr=no_parse_addresses) if type(item) is list: item.reverse() listlength = len(item) for listitem in item: subitem = PromptUtils.parse_param( listitem, wallet, parse_addr=no_parse_addresses) if type(subitem) is list: subitem.reverse() for listitem2 in subitem: subsub = PromptUtils.parse_param( listitem2, wallet, parse_addr=no_parse_addresses) sb.push(subsub) sb.push(len(subitem)) sb.Emit(PACK) else: sb.push(subitem) sb.push(listlength) sb.Emit(PACK) else: sb.push(item) sb.EmitAppCall(shash.Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract_state.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput( AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract_state.Code.ScriptHash()) outputs.append(output) itx = InvocationTransaction() itx.Version = 1 itx.outputs = outputs itx.inputs = [] itx.scripts = [] itx.Attributes = deepcopy(invoke_attrs) if invoke_attrs else [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1 and not owners: contract = wallet.GetDefaultContract() itx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) itx.Attributes = make_unique_script_attr(itx.Attributes) try: itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) except (ValueError, TXFeeError): pass context = ContractParametersContext(itx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: itx.Attributes.append( TransactionAttribute( usage=TransactionAttributeUsage.Script, data=owner)) itx.Attributes = make_unique_script_attr(itx.Attributes) context = ContractParametersContext(itx, isMultiSig=True) if context.Completed: itx.scripts = context.GetScripts() else: logger.warn( "Not gathering signatures for test build. For a non-test invoke that would occur here." ) # if not gather_signatures(context, itx, owners): # return None, [], 0, None # print("gathered signatures %s " % itx.scripts) engine = ApplicationEngine(trigger_type=TriggerType.Application, container=itx, table=script_table, service=service, gas=itx.Gas, testMode=invocation_test_mode) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) i_success = engine.Execute() service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: service.TestCommit() if len(service.notifications) > 0: for n in service.notifications: Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None
def test_gather_param(self): 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') with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='1') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=1.03) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Integer) self.assertEqual(result, 1) 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) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="b'abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual(result, bytearray(b'abc')) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="abc") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, True) with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value=0) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Boolean) self.assertEqual(result, False) # test ContractParameterType.ByteArray for address input with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value='AeV59NyZtgj5AMQ7vY6yhr2MRvcfFeLWSb' ) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.ByteArray) self.assertEqual( result, bytearray( b'\xf9\x1dkp\x85\xdb|Z\xaf\t\xf1\x9e\xee\xc1\xca<\r\xb2\xc6\xec' )) 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) self.assertEqual(result, ['a', 'b', 'c']) with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"]') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array) self.assertEqual(result, ['a', 'b', 'c', [1, 3, 4], 'e']) # test ContractParameterType.Array without a closed list with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value='["a","b","c", [1, 3, 4], "e"') as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array, do_continue=False) self.assertEqual(result, None) self.assertEqual(abort, True) # test ContractParameterType.Array with no list with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="b'abc'") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Array, do_continue=False) self.assertRaises(Exception, "Please provide a list") self.assertEqual(result, None) self.assertEqual(abort, True) # test ContractParameterType.PublicKey with mock.patch( 'neo.Prompt.Utils.get_input_prompt', return_value= "03cbb45da6072c14761c9da545749d9cfd863f860c351066d16df480602a2024c6" ) as fake_prompt: test_wallet_path = shutil.copyfile( WalletFixtureTestCase.wallet_1_path(), WalletFixtureTestCase.wallet_1_dest()) wallet = UserWallet.Open( test_wallet_path, to_aes_key(WalletFixtureTestCase.wallet_1_pass())) addr_scripthash = wallet.GetStandardAddress() result, abort = Utils.gather_param(0, ContractParameterType.PublicKey) script = b'21' + result.encode_point(True) + b'ac' pk_script_hash = Crypto.ToScriptHash(script) self.assertEqual( addr_scripthash, pk_script_hash ) # verifies the functionality of ContractParameterType.PublicKey wallet.Close() wallet = None os.remove(WalletFixtureTestCase.wallet_1_dest()) # test ContractParameterType.PublicKey with bad public key with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="blah") as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.PublicKey) self.assertIsNone(result) self.assertTrue(abort) # test unknown ContractParameterType with mock.patch('neo.Prompt.Utils.get_input_prompt', return_value="9698b1cac6ce9cbe8517e490778525b929e01903" ) as fake_prompt: result, abort = Utils.gather_param(0, ContractParameterType.Hash160, do_continue=False) self.assertRaises(Exception, "Unknown param type Hash160") self.assertEqual(result, None) self.assertEqual(abort, True) # test Exception with mock.patch('sys.stdout', new=StringIO()) as mock_print: with mock.patch( 'neo.Prompt.Utils.get_input_prompt') as fake_prompt: fake_prompt.side_effect = [ Exception(-32602, "Invalid params"), KeyboardInterrupt ] result, abort = Utils.gather_param( 0, ContractParameterType.String) self.assertEqual(result, None) self.assertEqual(abort, True) self.assertIn("Invalid params", mock_print.getvalue()) # test KeyboardInterrupt with mock.patch('sys.stdout', new=StringIO()) as mock_print: with mock.patch( 'neo.Prompt.Utils.get_input_prompt') as fake_prompt: fake_prompt.side_effect = [KeyboardInterrupt] result, abort = Utils.gather_param( 0, ContractParameterType.String) self.assertEqual(result, None) self.assertEqual(abort, True) self.assertIn("Input cancelled", mock_print.getvalue())
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): if settings.USE_DEBUG_STORAGE: debug_storage = DebugStorage.instance() storages = DBInterface(debug_storage.db, DBPrefix.ST_Storage, StorageItem) storages.DebugStorage = True dtx = InvocationTransaction() dtx.Version = 1 dtx.outputs = [] dtx.inputs = [] dtx.scripts = [] dtx.Script = binascii.unhexlify(deploy_script) if from_addr is not None: from_addr = PromptUtils.lookup_addr_str(wallet, from_addr) try: dtx = wallet.MakeTransaction(tx=dtx, from_addr=from_addr) except (ValueError): pass context = ContractParametersContext(dtx) wallet.Sign(context) dtx.scripts = context.GetScripts() contract = wallet.GetDefaultContract() dtx.Attributes = [TransactionAttribute(usage=TransactionAttributeUsage.Script, data=Crypto.ToScriptHash(contract.Script, unhex=False))] dtx.Attributes = make_unique_script_attr(dtx.Attributes) to_dispatch = [] if snapshot is None: snapshot = GetBlockchain()._db.createSnapshot().Clone() engine = ApplicationEngine( trigger_type=TriggerType.Application, container=dtx, snapshot=snapshot, gas=dtx.Gas, testMode=True ) engine.LoadScript(dtx.Script) # first we will execute the test deploy # then right after, we execute the test invoke if enable_debugger: debugger = Debugger(engine) d_success = debugger.Execute() else: d_success = engine.Execute() # the old setup provided the same StateMachine object to the ApplicationEngine for deploy and invoke # this allowed for a single dispatch of events at the end of the function. Now a new StateMachine is automatically # created when creating an ApplicationEngine, thus we have to dispatch events after the deploy to not lose them as # testcases expect them to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) to_dispatch = [] if d_success: items = engine.ResultStack.Items contract_state = None for i in items: if type(i) is ContractState: contract_state = i break elif type(i) is InteropInterface: item = i.GetInterface() if type(item) is ContractState: contract_state = item break shash = contract_state.Code.ScriptHash() 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.reverse() sb = ScriptBuilder() for p in invoke_args: process_params(sb, p, wallet, no_parse_addresses) sb.EmitAppCall(shash.Data) out = sb.ToArray() outputs = [] if neo_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemShare().Hash, Value=neo_to_attach, script_hash=contract_state.Code.ScriptHash(), ) outputs.append(output) if gas_to_attach: output = TransactionOutput(AssetId=Blockchain.SystemCoin().Hash, Value=gas_to_attach, script_hash=contract_state.Code.ScriptHash()) outputs.append(output) itx = InvocationTransaction() itx.Version = 1 itx.outputs = outputs itx.inputs = [] itx.scripts = [] itx.Attributes = deepcopy(invoke_attrs) if invoke_attrs else [] itx.Script = binascii.unhexlify(out) if len(outputs) < 1 and not owners: contract = wallet.GetDefaultContract() itx.Attributes.append(TransactionAttribute(usage=TransactionAttributeUsage.Script, data=contract.ScriptHash)) itx.Attributes = make_unique_script_attr(itx.Attributes) try: itx = wallet.MakeTransaction(tx=itx, from_addr=from_addr) except (ValueError): pass context = ContractParametersContext(itx) wallet.Sign(context) if owners: owners = list(owners) for owner in owners: itx.Attributes.append(TransactionAttribute(usage=TransactionAttributeUsage.Script, data=owner)) itx.Attributes = make_unique_script_attr(itx.Attributes) context = ContractParametersContext(itx, isMultiSig=True) if context.Completed: itx.scripts = context.GetScripts() else: logger.warn("Not gathering signatures for test build. For a non-test invoke that would occur here.") engine = ApplicationEngine( trigger_type=TriggerType.Application, container=itx, snapshot=snapshot, gas=itx.Gas, testMode=invocation_test_mode ) engine.invocation_args = invoke_args engine.LoadScript(itx.Script) engine.LoadDebugInfoForScriptHash(debug_map, shash.Data) if enable_debugger: debugger = Debugger(engine) i_success = debugger.Execute() else: i_success = engine.Execute() engine._Service.ExecutionCompleted(engine, i_success) to_dispatch = to_dispatch + engine._Service.events_to_dispatch for event in to_dispatch: events.emit(event.event_type, event) if i_success: if len(engine._Service.notifications) > 0: for n in engine._Service.notifications: Blockchain.Default().OnNotify(n) logger.info("Used %s Gas " % engine.GasConsumed().ToString()) consumed = engine.GasConsumed() - Fixed8.FromDecimal(10) consumed = consumed.Ceil() if consumed <= Fixed8.Zero(): consumed = min_fee total_ops = engine.ops_processed # set the amount of gas the tx will need itx.Gas = consumed itx.Attributes = [] result = engine.ResultStack.Items return itx, result, total_ops, engine else: print("error executing invoke contract...") else: print("error executing deploy contract.....") # service.ExecutionCompleted(engine, False, 'error') return None, [], 0, None