Search in sources :

Example 1 with CreateContractData

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

the class ContractResource method export.

@GET
@Path("/export/{address}")
@ApiOperation(value = "导出合约编译代码的jar包 ")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public void export(@ApiParam(name = "address", value = "账户地址", required = true) @PathParam("address") String address, @Context HttpServletResponse response) {
    try {
        if (StringUtils.isBlank(address)) {
            return;
        }
        if (!AddressTool.validAddress(address)) {
            return;
        }
        byte[] contractAddressBytes = AddressTool.getAddress(address);
        if (!ContractLedgerUtil.isExistContractAddress(contractAddressBytes)) {
            return;
        }
        byte[] addressBytes = AddressTool.getAddress(address);
        Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(addressBytes);
        ContractAddressInfoPo po = contractAddressInfoResult.getData();
        if (po == null) {
            return;
        }
        Transaction tx = ledgerService.getTx(po.getCreateTxHash());
        CreateContractTransaction create = (CreateContractTransaction) tx;
        CreateContractData createTxData = create.getTxData();
        byte[] code = createTxData.getCode();
        // 1.设置文件ContentType类型,这样设置,会自动判断下载文件类型
        response.setContentType("application/octet-stream");
        // 2.设置文件头:最后一个参数是设置下载文件名
        response.addHeader("Content-Disposition", "attachment;filename=" + address + ".jar");
        response.getOutputStream().write(code);
        response.getOutputStream().flush();
    } catch (Exception e) {
        Log.error("Export Exception!");
    }
}
Also used : ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) NulsException(io.nuls.kernel.exception.NulsException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException)

Example 2 with CreateContractData

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

the class CreateContractTxValidator method validate.

@Override
public ValidateResult validate(CreateContractTransaction tx) throws NulsException {
    CreateContractData txData = tx.getTxData();
    byte[] sender = txData.getSender();
    byte[] contractAddress = txData.getContractAddress();
    if (!ContractUtil.isLegalContractAddress(contractAddress)) {
        Log.error("contract create error: Illegal contract address.");
        return ValidateResult.getFailedResult(this.getClass().getSimpleName(), ContractErrorCode.ILLEGAL_CONTRACT_ADDRESS);
    }
    Set<String> addressSet = SignatureUtil.getAddressFromTX(tx);
    if (!addressSet.contains(AddressTool.getStringAddressByBytes(sender))) {
        Log.error("contract create error: The contract creater is not the transaction creator.");
        return ValidateResult.getFailedResult(this.getClass().getSimpleName(), TransactionErrorCode.TX_DATA_VALIDATION_ERROR);
    }
    Na realFee = tx.getCoinData().getFee();
    Na fee = TransactionFeeCalculator.getTransferFee(tx.size()).add(Na.valueOf(LongUtils.mul(txData.getGasLimit(), txData.getPrice())));
    if (realFee.isGreaterOrEquals(fee)) {
        return ValidateResult.getSuccessResult();
    } else {
        Log.error("contract create error: The contract transaction fee is not right.");
        return ValidateResult.getFailedResult(this.getClass().getName(), TransactionErrorCode.FEE_NOT_RIGHT);
    }
}
Also used : Na(io.nuls.kernel.model.Na) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData)

Example 3 with CreateContractData

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

the class ContractTxServiceImpl method contractCreateTx.

/**
 * 创建生成智能合约的交易
 * 如果是创建合约的交易,交易仅仅用于创建合约,合约内部不执行复杂逻辑
 *
 * @param sender       交易创建者
 * @param gasLimit     最大gas消耗
 * @param price        执行合约单价
 * @param contractCode 合约代码
 * @param args         参数列表
 * @param password     账户密码
 * @param remark       备注
 * @return
 */
@Override
public Result contractCreateTx(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;
        }
        if (!accountResult.getData().isOk()) {
            return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
        }
        if (!ContractUtil.checkPrice(price.longValue())) {
            return Result.getFailed(ContractErrorCode.CONTRACT_MINIMUM_PRICE);
        }
        Account account = accountResult.getData();
        // 验证账户密码
        if (account.isEncrypted() && account.isLocked()) {
            AssertUtil.canNotEmpty(password, "the password can not be empty");
            if (!account.validatePassword(password)) {
                return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
            }
        }
        // 生成一个地址作为智能合约地址
        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();
        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() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
        }
        coinData.setFrom(coinDataResult.getCoinList());
        // 找零的UTXO
        if (coinDataResult.getChange() != null) {
            coinData.getTo().add(coinDataResult.getChange());
        }
        tx.setCoinData(coinData);
        tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
        // 生成签名
        List<ECKey> signEckeys = new ArrayList<>();
        List<ECKey> scriptEckeys = new ArrayList<>();
        ECKey eckey = account.getEcKey(password);
        // 如果最后一位为1则表示该交易包含普通签名
        if ((coinDataResult.getSignType() & 0x01) == 0x01) {
            signEckeys.add(eckey);
        }
        // 如果倒数第二位位为1则表示该交易包含脚本签名
        if ((coinDataResult.getSignType() & 0x02) == 0x02) {
            scriptEckeys.add(eckey);
        }
        SignatureUtil.createTransactionSignture(tx, scriptEckeys, signEckeys);
        // 保存未确认交易到本地账本
        Result saveResult = accountLedgerService.verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                Result rs = accountLedgerService.getMaxAmountOfOnce(senderBytes, tx, TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
                if (rs.isSuccess()) {
                    Na maxAmount = (Na) rs.getData();
                    rs = Result.getFailed(KernelErrorCode.DATA_SIZE_ERROR_EXTEND);
                    rs.setMsg(rs.getMsg() + maxAmount.toDouble());
                }
                return rs;
            }
            return saveResult;
        }
        // 广播交易
        Result sendResult = transactionService.broadcastTx(tx);
        if (sendResult.isFailed()) {
            accountLedgerService.deleteTransaction(tx);
            return sendResult;
        }
        Map<String, String> resultMap = MapUtil.createHashMap(2);
        String txHash = tx.getHash().getDigestHex();
        String contractAddressStr = AddressTool.getStringAddressByBytes(contractAddressBytes);
        resultMap.put("txHash", txHash);
        resultMap.put("contractAddress", contractAddressStr);
        // 保留未确认的创建合约交易到内存中
        this.saveLocalUnconfirmedCreateContractTransaction(sender, resultMap, tx.getTime());
        return Result.getSuccess().setData(resultMap);
    } catch (IOException e) {
        Log.error(e);
        Result result = Result.getFailed(ContractErrorCode.CONTRACT_TX_CREATE_ERROR);
        result.setMsg(e.getMessage());
        return result;
    } 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) ECKey(io.nuls.core.tools.crypto.ECKey) ContractResult(io.nuls.contract.dto.ContractResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsException(io.nuls.kernel.exception.NulsException) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData)

Example 4 with CreateContractData

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

the class ContractSdkResource method createContractTx.

@POST
@Path("/sdk/create")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "create contact transaction")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult createContractTx(@ApiParam(name = "createForm", value = "create contact transaction", required = true) CreateContractTx createContractTx) {
    if (!AddressTool.validAddress(createContractTx.getSender())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (createContractTx.getGasLimit() < 0 || createContractTx.getPrice() < 0) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (createContractTx.getUtxos().isEmpty()) {
        // utxo not null and size not zero.
        return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
    }
    Long gasLimit = createContractTx.getGasLimit();
    Long price = createContractTx.getPrice();
    Na value = Na.ZERO;
    long totalGas = LongUtils.mul(gasLimit, price);
    Na totalNa = Na.valueOf(totalGas);
    byte[] senderBytes = AddressTool.getAddress(createContractTx.getSender());
    /**
     * first create a new contract address.
     */
    Address contractAddress = null;
    try {
        contractAddress = AccountTool.createContractAddress();
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    byte[] contractAddressBytes = contractAddress.getAddressBytes();
    // 组装txData
    String contractCode = createContractTx.getContractCode();
    byte[] contractCodeBytes = Hex.decode(contractCode);
    CreateContractData txData = new CreateContractData();
    txData.setSender(senderBytes);
    txData.setContractAddress(contractAddressBytes);
    txData.setValue(value.getValue());
    txData.setGasLimit(gasLimit);
    txData.setPrice(price);
    txData.setCodeLen(contractCodeBytes.length);
    txData.setCode(contractCodeBytes);
    Object[] args = createContractTx.getArgs();
    if (args != null) {
        txData.setArgsCount((byte) args.length);
        if (args.length > 0) {
            txData.setArgs(ContractUtil.twoDimensionalArray(args));
        }
    }
    /**
     * create create contract tx data
     */
    CreateContractTransaction tx = new CreateContractTransaction();
    String remark = createContractTx.getRemark();
    if (StringUtils.isNotBlank(remark)) {
        try {
            tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    tx.setTime(TimeService.currentTimeMillis());
    tx.setTxData(txData);
    List<Coin> coinList = ConvertCoinTool.convertCoinList(createContractTx.getUtxos());
    CoinDataResult coinDataResult = CoinDataTool.getCoinData(senderBytes, totalNa, tx.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
    if (!coinDataResult.isEnough()) {
        return RpcClientResult.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
    }
    /**
     * build coin data
     */
    CoinData coinData = new CoinData();
    coinData.setFrom(coinDataResult.getCoinList());
    if (coinDataResult.getChange() != null) {
        coinData.getTo().add(coinDataResult.getChange());
    }
    tx.setCoinData(coinData);
    // 重置为0,重新计算交易对象的size
    tx.setSize(0);
    if (tx.getSize() > TxMaxSizeValidator.MAX_TX_SIZE) {
        return Result.getFailed(TransactionErrorCode.DATA_SIZE_ERROR).toRpcClientResult();
    }
    return this.buildReturnInfo(tx, AddressTool.getStringAddressByBytes(contractAddressBytes));
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) NulsException(io.nuls.kernel.exception.NulsException) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 5 with CreateContractData

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

the class ContractTransactionDto method makeTxData.

private Map<String, Object> makeTxData(Transaction tx) {
    Map<String, Object> result = new HashMap<>();
    TransactionLogicData txData = tx.getTxData();
    if (type == ContractConstant.TX_TYPE_CREATE_CONTRACT) {
        CreateContractData create = (CreateContractData) txData;
        result.put("data", new CreateContractDataDto(create));
    } else if (type == ContractConstant.TX_TYPE_CALL_CONTRACT) {
        CallContractData call = (CallContractData) txData;
        result.put("data", new CallContractDataDto(call));
    } else if (type == ContractConstant.TX_TYPE_DELETE_CONTRACT) {
        DeleteContractData delete = (DeleteContractData) txData;
        result.put("data", new DeleteContractDataDto(delete));
    } else if (type == ContractConstant.TX_TYPE_CONTRACT_TRANSFER) {
        ContractTransferData transfer = (ContractTransferData) txData;
        result.put("data", new ContractTransferDataDto(transfer));
    } else if (type == NulsConstant.TX_TYPE_COINBASE) {
        Map<String, String> map = MapUtil.createLinkedHashMap(1);
        map.put("sender", EMPTY);
        result.put("data", map);
    }
    return result;
}
Also used : HashMap(java.util.HashMap) CallContractData(io.nuls.contract.entity.txdata.CallContractData) ContractTransferData(io.nuls.contract.entity.txdata.ContractTransferData) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) DeleteContractData(io.nuls.contract.entity.txdata.DeleteContractData) TransactionLogicData(io.nuls.kernel.model.TransactionLogicData)

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