Search in sources :

Example 1 with ErrorException

use of io.nuls.contract.vm.exception.ErrorException in project nuls by nuls-io.

the class NativeAddress method transfer.

/**
 * native
 *
 * @see Address#transfer(BigInteger)
 */
private static Result transfer(MethodCode methodCode, MethodArgs methodArgs, Frame frame) {
    ObjectRef addressRef = methodArgs.objectRef;
    ObjectRef valueRef = (ObjectRef) methodArgs.invokeArgs[0];
    String address = frame.heap.runToString(addressRef);
    BigInteger value = frame.heap.toBigInteger(valueRef);
    byte[] from = frame.vm.getProgramInvoke().getContractAddress();
    byte[] to = NativeAddress.toBytes(address);
    if (Arrays.equals(from, to)) {
        throw new ErrorException(String.format("Cannot transfer from %s to %s", NativeAddress.toString(from), address), frame.vm.getGasUsed(), null);
    }
    checkBalance(from, value, frame);
    frame.vm.addGasUsed(GasCost.TRANSFER);
    if (frame.heap.existContract(to)) {
        // String address;
        String methodName = "_payable";
        String methodDesc = "()V";
        String[][] args = null;
        // BigInteger value;
        call(address, methodName, methodDesc, args, value, frame);
    } else {
        frame.vm.getProgramExecutor().getAccount(from).addBalance(value.negate());
        ProgramTransfer programTransfer = new ProgramTransfer(from, to, value);
        frame.vm.getTransfers().add(programTransfer);
    }
    Result result = NativeMethod.result(methodCode, null, frame);
    return result;
}
Also used : BigInteger(java.math.BigInteger) ErrorException(io.nuls.contract.vm.exception.ErrorException) ProgramTransfer(io.nuls.contract.vm.program.ProgramTransfer) ProgramResult(io.nuls.contract.vm.program.ProgramResult)

Example 2 with ErrorException

use of io.nuls.contract.vm.exception.ErrorException in project nuls by nuls-io.

the class NativeAddress method call.

private static String call(String address, String methodName, String methodDesc, String[][] args, BigInteger value, Frame frame) {
    if (value.compareTo(BigInteger.ZERO) < 0) {
        throw new ErrorException(String.format("amount less than zero, value=%s", value), frame.vm.getGasUsed(), null);
    }
    ProgramInvoke programInvoke = frame.vm.getProgramInvoke();
    ProgramCall programCall = new ProgramCall();
    programCall.setNumber(programInvoke.getNumber());
    programCall.setSender(programInvoke.getContractAddress());
    programCall.setValue(value != null ? value : BigInteger.ZERO);
    programCall.setGasLimit(programInvoke.getGasLimit() - frame.vm.getGasUsed());
    programCall.setPrice(programInvoke.getPrice());
    programCall.setContractAddress(NativeAddress.toBytes(address));
    programCall.setMethodName(methodName);
    programCall.setMethodDesc(methodDesc);
    programCall.setArgs(args);
    programCall.setEstimateGas(programInvoke.isEstimateGas());
    programCall.setViewMethod(programInvoke.isViewMethod());
    programCall.setInternalCall(true);
    if (programCall.getValue().compareTo(BigInteger.ZERO) > 0) {
        checkBalance(programCall.getSender(), programCall.getValue(), frame);
        frame.vm.getProgramExecutor().getAccount(programCall.getSender()).addBalance(programCall.getValue().negate());
        ProgramTransfer programTransfer = new ProgramTransfer(programCall.getSender(), programCall.getContractAddress(), programCall.getValue());
        frame.vm.getTransfers().add(programTransfer);
    }
    ProgramResult programResult = frame.vm.getProgramExecutor().callProgramExecutor().call(programCall);
    frame.vm.addGasUsed(programResult.getGasUsed());
    if (programResult.isSuccess()) {
        frame.vm.getTransfers().addAll(programResult.getTransfers());
        frame.vm.getEvents().addAll(programResult.getEvents());
        return programResult.getResult();
    } else if (programResult.isError()) {
        // return null;
        throw new ErrorException(programResult.getErrorMessage(), programResult.getGasUsed(), programResult.getStackTrace());
    } else {
        throw new RuntimeException("error contract status");
    }
}
Also used : ProgramInvoke(io.nuls.contract.vm.program.impl.ProgramInvoke) ProgramResult(io.nuls.contract.vm.program.ProgramResult) ErrorException(io.nuls.contract.vm.exception.ErrorException) ProgramCall(io.nuls.contract.vm.program.ProgramCall) ProgramTransfer(io.nuls.contract.vm.program.ProgramTransfer)

Example 3 with ErrorException

use of io.nuls.contract.vm.exception.ErrorException in project nuls by nuls-io.

the class ProgramExecutorImpl method execute.

private ProgramResult execute(ProgramInvoke programInvoke) {
    if (programInvoke.getPrice() < 1) {
        return revert("gas price must be greater than zero");
    }
    if (programInvoke.getGasLimit() < 1) {
        return revert("gas must be greater than zero");
    }
    long maxGas;
    if (programInvoke.isViewMethod()) {
        maxGas = VMContext.getCustomMaxViewGasLimit();
    } else {
        maxGas = VM.MAX_GAS;
    }
    if (programInvoke.getGasLimit() > maxGas) {
        return revert("gas must be less than " + maxGas);
    }
    if (programInvoke.getValue().compareTo(BigInteger.ZERO) < 0) {
        return revert("value can't be less than zero");
    }
    blockNumber = programInvoke.getNumber();
    logTime("start");
    try {
        Map<String, ClassCode> classCodes;
        if (programInvoke.isCreate()) {
            if (programInvoke.getData() == null) {
                return revert("contract code can't be null");
            }
            classCodes = ClassCodeLoader.loadJarCache(programInvoke.getData());
            logTime("load new code");
            ProgramChecker.check(classCodes);
            logTime("check code");
            AccountState accountState = repository.getAccountState(programInvoke.getContractAddress());
            if (accountState != null) {
                return revert(String.format("contract[%s] already exists", programInvoke.getAddress()));
            }
            accountState = repository.createAccount(programInvoke.getContractAddress(), programInvoke.getSender());
            logTime("new account state");
            repository.saveCode(programInvoke.getContractAddress(), programInvoke.getData());
            logTime("save code");
        } else {
            if ("<init>".equals(programInvoke.getMethodName())) {
                return revert("can't invoke <init> method");
            }
            AccountState accountState = repository.getAccountState(programInvoke.getContractAddress());
            if (accountState == null) {
                return revert(String.format("contract[%s] does not exist", programInvoke.getAddress()));
            }
            logTime("load account state");
            if (accountState.getNonce().compareTo(BigInteger.ZERO) <= 0) {
                return revert(String.format("contract[%s] has stopped", programInvoke.getAddress()));
            }
            byte[] codes = repository.getCode(programInvoke.getContractAddress());
            classCodes = ClassCodeLoader.loadJarCache(codes);
            logTime("load code");
        }
        VM vm = VMFactory.createVM();
        logTime("load vm");
        vm.heap.loadClassCodes(classCodes);
        vm.methodArea.loadClassCodes(classCodes);
        logTime("load classes");
        ClassCode contractClassCode = getContractClassCode(classCodes);
        String methodDesc = ProgramDescriptors.parseDesc(programInvoke.getMethodDesc());
        MethodCode methodCode = vm.methodArea.loadMethod(contractClassCode.name, programInvoke.getMethodName(), methodDesc);
        if (methodCode == null) {
            return revert(String.format("can't find method %s%s", programInvoke.getMethodName(), programInvoke.getMethodDesc() == null ? "" : programInvoke.getMethodDesc()));
        }
        if (!methodCode.isPublic) {
            return revert("can only invoke public method");
        }
        if (!methodCode.hasPayableAnnotation() && programInvoke.getValue().compareTo(BigInteger.ZERO) > 0) {
            return revert("not a payable method");
        }
        if (methodCode.argsVariableType.size() != programInvoke.getArgs().length) {
            return revert(String.format("require %s parameters in method [%s%s]", methodCode.argsVariableType.size(), methodCode.name, methodCode.normalDesc));
        }
        logTime("load method");
        ObjectRef objectRef;
        if (programInvoke.isCreate()) {
            objectRef = vm.heap.newContract(programInvoke.getContractAddress(), contractClassCode, repository);
        } else {
            objectRef = vm.heap.loadContract(programInvoke.getContractAddress(), contractClassCode, repository);
        }
        logTime("load contract ref");
        if (programInvoke.getValue().compareTo(BigInteger.ZERO) > 0) {
            getAccount(programInvoke.getContractAddress()).addBalance(programInvoke.getValue());
        }
        vm.setProgramExecutor(this);
        vm.setRepository(repository);
        vm.setGas(programInvoke.getGasLimit());
        vm.addGasUsed(programInvoke.getData() == null ? 0 : programInvoke.getData().length);
        logTime("load end");
        vm.run(objectRef, methodCode, vmContext, programInvoke);
        logTime("run");
        ProgramResult programResult = new ProgramResult();
        programResult.setGasUsed(vm.getGasUsed());
        Result vmResult = vm.getResult();
        Object resultValue = vmResult.getValue();
        if (vmResult.isError() || vmResult.isException()) {
            if (resultValue != null && resultValue instanceof ObjectRef) {
                vm.setResult(new Result());
                String error = vm.heap.runToString((ObjectRef) resultValue);
                String stackTrace = vm.heap.stackTrace((ObjectRef) resultValue);
                programResult.error(error);
                programResult.setStackTrace(stackTrace);
            } else {
                programResult.error(null);
            }
            logTime("contract exception");
            this.revert = true;
            programResult.setGasUsed(vm.getGasUsed());
            return programResult;
        }
        programResult.setTransfers(vm.getTransfers());
        programResult.setEvents(vm.getEvents());
        programResult.setBalance(getAccount(programInvoke.getContractAddress()).getBalance());
        if (resultValue != null) {
            if (resultValue instanceof ObjectRef) {
                String result = vm.heap.runToString((ObjectRef) resultValue);
                programResult.setResult(result);
            } else {
                programResult.setResult(resultValue.toString());
            }
        }
        if (methodCode.isPublic && methodCode.hasViewAnnotation()) {
            this.revert = true;
            programResult.view();
            programResult.setGasUsed(vm.getGasUsed());
            return programResult;
        }
        logTime("contract return");
        Map<DataWord, DataWord> contractState = vm.heap.contractState();
        logTime("contract state");
        for (Map.Entry<DataWord, DataWord> entry : contractState.entrySet()) {
            DataWord key = entry.getKey();
            DataWord value = entry.getValue();
            repository.addStorageRow(programInvoke.getContractAddress(), key, value);
        }
        logTime("add contract state");
        repository.increaseNonce(programInvoke.getContractAddress());
        programResult.setNonce(repository.getNonce(programInvoke.getContractAddress()));
        programResult.setGasUsed(vm.getGasUsed());
        return programResult;
    } catch (ErrorException e) {
        this.revert = true;
        // log.error("", e);
        ProgramResult programResult = new ProgramResult();
        programResult.setGasUsed(e.getGasUsed());
        // programResult.setStackTrace(e.getStackTraceMessage());
        logTime("error");
        return programResult.error(e.getMessage());
    } catch (Exception e) {
        log.error("", e);
        ProgramResult programResult = revert(e.getMessage());
        // programResult.setStackTrace(ExceptionUtils.getStackTrace(e));
        return programResult;
    }
}
Also used : DataWord(org.ethereum.vm.DataWord) AccountState(org.ethereum.core.AccountState) ErrorException(io.nuls.contract.vm.exception.ErrorException) Result(io.nuls.contract.vm.Result) ClassCode(io.nuls.contract.vm.code.ClassCode) VM(io.nuls.contract.vm.VM) MethodCode(io.nuls.contract.vm.code.MethodCode) ObjectRef(io.nuls.contract.vm.ObjectRef) ErrorException(io.nuls.contract.vm.exception.ErrorException)

Aggregations

ErrorException (io.nuls.contract.vm.exception.ErrorException)3 ProgramResult (io.nuls.contract.vm.program.ProgramResult)2 ProgramTransfer (io.nuls.contract.vm.program.ProgramTransfer)2 ObjectRef (io.nuls.contract.vm.ObjectRef)1 Result (io.nuls.contract.vm.Result)1 VM (io.nuls.contract.vm.VM)1 ClassCode (io.nuls.contract.vm.code.ClassCode)1 MethodCode (io.nuls.contract.vm.code.MethodCode)1 ProgramCall (io.nuls.contract.vm.program.ProgramCall)1 ProgramInvoke (io.nuls.contract.vm.program.impl.ProgramInvoke)1 BigInteger (java.math.BigInteger)1 AccountState (org.ethereum.core.AccountState)1 DataWord (org.ethereum.vm.DataWord)1