Search in sources :

Example 6 with CreateContractData

use of io.nuls.contract.entity.txdata.CreateContractData in project nuls by nuls-io.

the class ContractTxServiceImpl method contractPreCreateTx.

/**
 * 预创建生成智能合约的交易
 * 用于测试合约是否能正确创建
 *
 * @param sender       交易创建者
 * @param gasLimit     最大gas消耗
 * @param price        执行合约单价
 * @param contractCode 合约代码
 * @param args         参数列表
 * @param password     账户密码
 * @param remark       备注
 * @return
 */
@Override
public Result contractPreCreateTx(String sender, Long gasLimit, Long price, byte[] contractCode, String[][] args, String password, String remark) {
    try {
        AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
        AssertUtil.canNotEmpty(contractCode, "the contractCode can not be empty");
        Na value = Na.ZERO;
        Result<Account> accountResult = accountService.getAccount(sender);
        if (accountResult.isFailed()) {
            return accountResult;
        }
        // 生成一个地址作为智能合约地址
        Address contractAddress = AccountTool.createContractAddress();
        byte[] contractAddressBytes = contractAddress.getAddressBytes();
        byte[] senderBytes = AddressTool.getAddress(sender);
        CreateContractTransaction tx = new CreateContractTransaction();
        if (StringUtils.isNotBlank(remark)) {
            try {
                tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                Log.error(e);
                throw new RuntimeException(e);
            }
        }
        tx.setTime(TimeService.currentTimeMillis());
        // 计算CoinData
        /*
             * 智能合约计算手续费以消耗的Gas*Price为根据,然而创建交易时并不执行智能合约,
             * 所以此时交易的CoinData是不固定的,比实际要多,
             * 打包时执行智能合约,真实的手续费已算出,然而tx的手续费已扣除,
             * 多扣除的费用会以CoinBase交易还给Sender
             */
        CoinData coinData = new CoinData();
        // 向智能合约账户转账
        if (!Na.ZERO.equals(value)) {
            Coin toCoin = new Coin(contractAddressBytes, value);
            coinData.getTo().add(toCoin);
        }
        BlockHeader blockHeader = NulsContext.getInstance().getBestBlock().getHeader();
        // 当前区块高度
        long blockHeight = blockHeader.getHeight();
        // 当前区块状态根
        byte[] prevStateRoot = ContractUtil.getStateRoot(blockHeader);
        AssertUtil.canNotEmpty(prevStateRoot, "All features of the smart contract are locked.");
        // 执行VM验证合法性
        ProgramCreate programCreate = new ProgramCreate();
        programCreate.setContractAddress(contractAddressBytes);
        programCreate.setSender(senderBytes);
        programCreate.setValue(BigInteger.valueOf(value.getValue()));
        programCreate.setPrice(price.longValue());
        programCreate.setGasLimit(gasLimit.longValue());
        programCreate.setNumber(blockHeight);
        programCreate.setContractCode(contractCode);
        if (args != null) {
            programCreate.setArgs(args);
        }
        ProgramExecutor track = programExecutor.begin(prevStateRoot);
        // 验证合约时跳过Gas验证
        long realGasLimit = programCreate.getGasLimit();
        programCreate.setGasLimit(MAX_GASLIMIT);
        ProgramResult programResult = track.create(programCreate);
        // 执行结果失败时,交易直接返回错误,不上链,不消耗Gas,
        if (!programResult.isSuccess()) {
            Log.error(programResult.getStackTrace());
            Result result = Result.getFailed(ContractErrorCode.DATA_ERROR);
            result.setMsg(ContractUtil.simplifyErrorMsg(programResult.getErrorMessage()));
            result = checkVmResultAndReturn(programResult.getErrorMessage(), result);
            return result;
        } else {
            // 其他合法性都通过后,再验证Gas
            track = programExecutor.begin(prevStateRoot);
            programCreate.setGasLimit(realGasLimit);
            programResult = track.create(programCreate);
            if (!programResult.isSuccess()) {
                Log.error(programResult.getStackTrace());
                Result result = Result.getFailed(ContractErrorCode.DATA_ERROR);
                result.setMsg(ContractUtil.simplifyErrorMsg(programResult.getErrorMessage()));
                return result;
            }
        }
        long gasUsed = gasLimit.longValue();
        Na imputedNa = Na.valueOf(LongUtils.mul(gasUsed, price));
        // 总花费
        Na totalNa = imputedNa.add(value);
        // 组装txData
        CreateContractData createContractData = new CreateContractData();
        createContractData.setSender(senderBytes);
        createContractData.setContractAddress(contractAddressBytes);
        createContractData.setValue(value.getValue());
        createContractData.setGasLimit(gasLimit);
        createContractData.setPrice(price);
        createContractData.setCodeLen(contractCode.length);
        createContractData.setCode(contractCode);
        if (args != null) {
            createContractData.setArgsCount((byte) args.length);
            if (args.length > 0) {
                createContractData.setArgs(args);
            }
        }
        tx.setTxData(createContractData);
        CoinDataResult coinDataResult = accountLedgerService.getCoinData(senderBytes, totalNa, tx.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
        }
        return Result.getSuccess();
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(e.getErrorCode());
    } catch (Exception e) {
        Log.error(e);
        Result result = Result.getFailed(ContractErrorCode.CONTRACT_TX_CREATE_ERROR);
        result.setMsg(e.getMessage());
        return result;
    }
}
Also used : Account(io.nuls.account.model.Account) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) ContractResult(io.nuls.contract.dto.ContractResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsException(io.nuls.kernel.exception.NulsException) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 7 with CreateContractData

use of io.nuls.contract.entity.txdata.CreateContractData in project nuls by nuls-io.

the class CreateContractTxProcessor method onRollback.

@Override
public Result onRollback(CreateContractTransaction tx, Object secondaryData) {
    CreateContractData txData = tx.getTxData();
    byte[] contractAddress = txData.getContractAddress();
    contractCollectionStorageService.deleteContractAddress(contractAddress);
    contractAddressStorageService.deleteContractAddress(contractAddress);
    contractService.deleteContractExecuteResult(tx.getHash());
    return Result.getSuccess();
}
Also used : CreateContractData(io.nuls.contract.entity.txdata.CreateContractData)

Example 8 with CreateContractData

use of io.nuls.contract.entity.txdata.CreateContractData in project nuls by nuls-io.

the class CreateContractTxProcessor method onCommit.

@Override
public Result onCommit(CreateContractTransaction tx, Object secondaryData) {
    ContractResult contractResult = tx.getContractResult();
    contractService.saveContractExecuteResult(tx.getHash(), contractResult);
    CreateContractData txData = tx.getTxData();
    byte[] contractAddress = txData.getContractAddress();
    byte[] sender = txData.getSender();
    String senderStr = AddressTool.getStringAddressByBytes(sender);
    String contractAddressStr = AddressTool.getStringAddressByBytes(contractAddress);
    // 移除未确认的创建合约交易
    contractTxService.removeLocalUnconfirmedCreateContractTransaction(senderStr, contractAddressStr, contractResult);
    // 执行失败的合约直接返回
    if (!contractResult.isSuccess()) {
        return Result.getSuccess();
    }
    NulsDigestData hash = tx.getHash();
    long blockHeight = tx.getBlockHeight();
    long bestBlockHeight = NulsContext.getInstance().getBestHeight();
    ContractAddressInfoPo info = new ContractAddressInfoPo();
    info.setContractAddress(contractAddress);
    info.setSender(sender);
    try {
        info.setCreateTxHash(hash.serialize());
    } catch (IOException e) {
        throw new NulsRuntimeException(e);
    }
    info.setCreateTime(tx.getTime());
    info.setBlockHeight(blockHeight);
    // byte[] stateRoot = contractResult.getStateRoot();
    boolean isNrc20Contract = contractResult.isNrc20();
    boolean acceptDirectTransfer = contractResult.isAcceptDirectTransfer();
    info.setAcceptDirectTransfer(acceptDirectTransfer);
    info.setNrc20(isNrc20Contract);
    // 获取 token tracker
    if (isNrc20Contract) {
        BlockHeader blockHeader = tx.getBlockHeader();
        byte[] newestStateRoot = blockHeader.getStateRoot();
        // NRC20 token 标准方法获取名称数据
        ProgramResult programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_NAME, null, null);
        if (programResult.isSuccess()) {
            String tokenName = programResult.getResult();
            info.setNrc20TokenName(tokenName);
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_SYMBOL, null, null);
        if (programResult.isSuccess()) {
            String symbol = programResult.getResult();
            info.setNrc20TokenSymbol(symbol);
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_DECIMALS, null, null);
        if (programResult.isSuccess()) {
            String decimals = programResult.getResult();
            if (StringUtils.isNotBlank(decimals)) {
                try {
                    info.setDecimals(new BigInteger(decimals).longValue());
                } catch (Exception e) {
                    Log.error("Get nrc20 decimals error.", e);
                // skip it
                }
            }
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_TOTAL_SUPPLY, null, null);
        if (programResult.isSuccess()) {
            String totalSupply = programResult.getResult();
            if (StringUtils.isNotBlank(totalSupply)) {
                try {
                    info.setTotalSupply(new BigInteger(totalSupply));
                } catch (Exception e) {
                    Log.error("Get nrc20 totalSupply error.", e);
                // skip it
                }
            }
        }
        // 刷新创建者的token余额
        vmHelper.refreshTokenBalance(newestStateRoot, info, senderStr, contractAddressStr);
        // 处理合约事件
        vmHelper.dealEvents(newestStateRoot, tx, contractResult, info);
    }
    Result result = contractAddressStorageService.saveContractAddress(contractAddress, info);
    return result;
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) ProgramResult(io.nuls.contract.vm.program.ProgramResult) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) ProgramResult(io.nuls.contract.vm.program.ProgramResult) Result(io.nuls.kernel.model.Result) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) NulsDigestData(io.nuls.kernel.model.NulsDigestData) BigInteger(java.math.BigInteger) BlockHeader(io.nuls.kernel.model.BlockHeader)

Example 9 with CreateContractData

use of io.nuls.contract.entity.txdata.CreateContractData in project nuls by nuls-io.

the class VMHelper method validateNrc20Contract.

public Result validateNrc20Contract(ProgramExecutor track, CreateContractTransaction tx, ContractResult contractResult) {
    if (contractResult == null) {
        return Result.getFailed(ContractErrorCode.NULL_PARAMETER);
    }
    CreateContractData createContractData = tx.getTxData();
    byte[] stateRoot = contractResult.getStateRoot();
    byte[] contractAddress = contractResult.getContractAddress();
    long bestBlockHeight = NulsContext.getInstance().getBestHeight();
    List<ProgramMethod> methods = this.getAllMethods(createContractData.getCode());
    boolean isNrc20 = this.checkNrc20Contract(methods);
    boolean isAcceptDirectTransfer = this.checkAcceptDirectTransfer(methods);
    contractResult.setNrc20(isNrc20);
    contractResult.setAcceptDirectTransfer(isAcceptDirectTransfer);
    if (isNrc20) {
        // NRC20 tokenName 验证代币名称格式
        ProgramResult programResult = this.invokeViewMethod(track, stateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_NAME, null, null);
        if (programResult.isSuccess()) {
            String tokenName = programResult.getResult();
            if (StringUtils.isNotBlank(tokenName)) {
                if (!StringUtils.validTokenNameOrSymbol(tokenName)) {
                    return Result.getFailed(ContractErrorCode.CONTRACT_NAME_FORMAT_INCORRECT);
                }
            }
        }
        // NRC20 tokenSymbol 验证代币符号的格式
        programResult = this.invokeViewMethod(track, stateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_SYMBOL, null, null);
        if (programResult.isSuccess()) {
            String symbol = programResult.getResult();
            if (StringUtils.isNotBlank(symbol)) {
                if (!StringUtils.validTokenNameOrSymbol(symbol)) {
                    return Result.getFailed(ContractErrorCode.CONTRACT_NRC20_SYMBOL_FORMAT_INCORRECT);
                }
            }
        }
        programResult = this.invokeViewMethod(track, stateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_DECIMALS, null, null);
        BigInteger decimalsBig = BigInteger.ZERO;
        if (programResult.isSuccess()) {
            String decimals = programResult.getResult();
            if (StringUtils.isNotBlank(decimals)) {
                try {
                    decimalsBig = new BigInteger(decimals);
                    if (decimalsBig.compareTo(BigInteger.ZERO) < 0 || decimalsBig.compareTo(MAXIMUM_DECIMALS) > 0) {
                        return Result.getFailed(ContractErrorCode.CONTRACT_NRC20_MAXIMUM_DECIMALS);
                    }
                } catch (Exception e) {
                    Log.error("Get nrc20 decimals error.", e);
                // skip it
                }
            }
        }
        programResult = this.invokeViewMethod(track, stateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_TOTAL_SUPPLY, null, null);
        if (programResult.isSuccess()) {
            String totalSupply = programResult.getResult();
            if (StringUtils.isNotBlank(totalSupply)) {
                try {
                    BigInteger totalSupplyBig = new BigInteger(totalSupply);
                    if (totalSupplyBig.compareTo(BigInteger.ZERO) <= 0 || totalSupplyBig.compareTo(MAXIMUM_TOTAL_SUPPLY.multiply(BigInteger.TEN.pow(decimalsBig.intValue()))) > 0) {
                        return Result.getFailed(ContractErrorCode.CONTRACT_NRC20_MAXIMUM_TOTAL_SUPPLY);
                    }
                } catch (Exception e) {
                    Log.error("Get nrc20 totalSupply error.", e);
                // skip it
                }
            }
        }
    }
    return Result.getSuccess();
}
Also used : CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) BigInteger(java.math.BigInteger) NulsException(io.nuls.kernel.exception.NulsException)

Aggregations

CreateContractData (io.nuls.contract.entity.txdata.CreateContractData)9 NulsException (io.nuls.kernel.exception.NulsException)6 CreateContractTransaction (io.nuls.contract.entity.tx.CreateContractTransaction)4 IOException (java.io.IOException)4 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)3 ContractResult (io.nuls.contract.dto.ContractResult)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)3 Account (io.nuls.account.model.Account)2 ContractAddressInfoPo (io.nuls.contract.storage.po.ContractAddressInfoPo)2 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)2 BigInteger (java.math.BigInteger)2 CallContractData (io.nuls.contract.entity.txdata.CallContractData)1 ContractTransferData (io.nuls.contract.entity.txdata.ContractTransferData)1 DeleteContractData (io.nuls.contract.entity.txdata.DeleteContractData)1 ProgramResult (io.nuls.contract.vm.program.ProgramResult)1 ECKey (io.nuls.core.tools.crypto.ECKey)1 BlockHeader (io.nuls.kernel.model.BlockHeader)1 Na (io.nuls.kernel.model.Na)1 NulsDigestData (io.nuls.kernel.model.NulsDigestData)1 Result (io.nuls.kernel.model.Result)1