def contract_call_internal(engine: contracts.ApplicationEngine, contract_hash: types.UInt160, method: str, args: vm.ArrayStackItem, flags: contracts.native.CallFlags) -> None: if method.startswith('_'): raise ValueError("[System.Contract.Call] Method not allowed to start with _") target_contract = engine.snapshot.contracts.try_get(contract_hash, read_only=True) if target_contract is None: raise ValueError("[System.Contract.Call] Can't find target contract") current_contract = engine.snapshot.contracts.try_get(engine.current_scripthash, read_only=True) if current_contract and not current_contract.manifest.can_call(target_contract.manifest, method): raise ValueError(f"[System.Contract.Call] Not allowed to call target method '{method}' according to manifest") counter = engine._invocation_counter.get(target_contract.script_hash(), 0) engine._invocation_counter.update({target_contract.script_hash(): counter + 1}) engine._get_invocation_state(engine.current_context).check_return_value = True state = engine.current_context calling_flags = state.call_flags contract_method_descriptor = target_contract.manifest.abi.get_method(method) if contract_method_descriptor is None: raise ValueError(f"[System.Contract.Call] requested target method '{method}' does not exist on target contract") arg_len = len(args) expected_len = len(contract_method_descriptor.parameters) if arg_len != expected_len: raise ValueError( f"[System.Contract.Call] Invalid number of contract arguments. Expected {expected_len} actual {arg_len}") # noqa context_new = engine.load_script(vm.Script(target_contract.script)) context_new.calling_script = state.script context_new.call_flags = flags & calling_flags if contracts.NativeContract.is_native(contract_hash): context_new.evaluation_stack.push(args) context_new.evaluation_stack.push(vm.ByteStringStackItem(method.encode('utf-8'))) else: for item in reversed(args): context_new.evaluation_stack.push(item) context_new.ip = contract_method_descriptor.offset contract_method_descriptor = target_contract.manifest.abi.get_method("_initialize") if contract_method_descriptor is not None: engine.load_cloned_context(contract_method_descriptor.offset)
def invoke_method_of_arbitrary_contract( self, contract_hash: Union[UInt160, Hash160Str, str], method: str, params: List = None, signers: List[Union[str, UInt160, payloads.Signer]] = None, scope: payloads.WitnessScope = payloads.WitnessScope.GLOBAL, engine: ApplicationEngine = None): if params is None: params = [] params = list(map(lambda param: self.param_auto_checker(param), params)) if not engine: engine = self.new_engine(self.previous_engine) contract_hash = self.contract_hash_auto_checker(contract_hash) # engine.load_script(vm.Script(contract.script)) sb = vm.ScriptBuilder() if params: sb.emit_dynamic_call_with_args(contract_hash, method, params) else: sb.emit_dynamic_call(contract_hash, method) engine.load_script(vm.Script(sb.to_array())) if signers and signers != self.NO_SIGNER: signers = list( map(lambda signer: self.signer_auto_checker(signer, scope), signers)) engine.script_container.signers = signers elif self.signers: # use signers stored in self when no external signer specified engine.script_container.signers = self.signers engine.execute() engine.snapshot.commit() self.previous_engine = engine return engine