예제 #1
0
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)
예제 #2
0
    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