Search in sources :

Example 1 with CallContractTransaction

use of io.nuls.contract.entity.tx.CallContractTransaction in project nuls by nuls-io.

the class CallContractTxProcessor method onRollback.

@Override
public Result onRollback(CallContractTransaction tx, Object secondaryData) {
    try {
        // 回滚代币转账交易
        byte[] txHashBytes = null;
        try {
            txHashBytes = tx.getHash().serialize();
        } catch (IOException e) {
            Log.error(e);
        }
        ContractResult contractResult = tx.getContractResult();
        if (contractResult == null) {
            contractResult = contractService.getContractExecuteResult(tx.getHash());
        }
        CallContractData txData = tx.getTxData();
        byte[] senderContractAddressBytes = txData.getContractAddress();
        Result<ContractAddressInfoPo> senderContractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(senderContractAddressBytes);
        ContractAddressInfoPo po = senderContractAddressInfoResult.getData();
        if (po != null) {
            if (contractResult != null) {
                // 处理合约执行失败 - 没有transferEvent的情况, 直接从数据库中删除
                if (!contractResult.isSuccess()) {
                    if (ContractUtil.isTransferMethod(txData.getMethodName())) {
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(txData.getSender(), txHashBytes, new VarInt(0).encode()));
                    }
                }
                List<String> events = contractResult.getEvents();
                int size = events.size();
                // 目前只处理Transfer事件
                String event;
                ContractAddressInfoPo contractAddressInfo;
                if (events != null && size > 0) {
                    for (int i = 0; i < size; i++) {
                        event = events.get(i);
                        // 按照NRC20标准,TransferEvent事件中第一个参数是转出地址-from,第二个参数是转入地址-to, 第三个参数是金额
                        ContractTokenTransferInfoPo tokenTransferInfoPo = ContractUtil.convertJsonToTokenTransferInfoPo(event);
                        if (tokenTransferInfoPo == null) {
                            continue;
                        }
                        String contractAddress = tokenTransferInfoPo.getContractAddress();
                        if (StringUtils.isBlank(contractAddress)) {
                            continue;
                        }
                        if (!AddressTool.validAddress(contractAddress)) {
                            continue;
                        }
                        byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
                        if (ArraysTool.arrayEquals(senderContractAddressBytes, contractAddressBytes)) {
                            contractAddressInfo = po;
                        } else {
                            Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(contractAddressBytes);
                            contractAddressInfo = contractAddressInfoResult.getData();
                        }
                        if (contractAddressInfo == null) {
                            continue;
                        }
                        // 事件不是NRC20合约的事件
                        if (!contractAddressInfo.isNrc20()) {
                            continue;
                        }
                        // 回滚token余额
                        this.rollbackContractToken(tokenTransferInfoPo);
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getFrom(), txHashBytes, new VarInt(i).encode()));
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getTo(), txHashBytes, new VarInt(i).encode()));
                    }
                }
            }
        }
        // 删除子交易从全网账本
        // 删除子交易从合约账本
        // 删除子交易从本地账本
        List<ContractTransferTransaction> contractTransferTxList = this.extractContractTransferTxs(contractResult);
        if (contractTransferTxList != null && !contractTransferTxList.isEmpty()) {
            // 用于回滚本地账本
            List<Transaction> txList = new ArrayList<>();
            for (ContractTransferTransaction transferTx : contractTransferTxList) {
                try {
                    txList.add(transferTx);
                    Result result = ledgerService.rollbackTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("rollback contract transfer tx from ledger error. msg: {}", result.getMsg());
                        return result;
                    }
                    result = contractService.rollbackContractTransferTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("rollback contract transfer tx from contract ledger error. msg: {}", result.getMsg());
                        return Result.getFailed();
                    }
                } catch (Exception e) {
                    Log.error("rollback contract transfer tx error. msg: {}", e.getMessage());
                    return Result.getFailed();
                }
            }
            Result result = accountLedgerService.rollbackTransactions(txList);
            if (result.isFailed()) {
                Log.error("rollback contract transfer tx from account ledger error. msg: {}", result.getMsg());
                return Result.getFailed();
            }
        }
        // 删除合约调用交易的UTXO
        contractUtxoService.deleteUtxoOfTransaction(tx);
        // 删除合约执行结果
        contractService.deleteContractExecuteResult(tx.getHash());
    } catch (Exception e) {
        Log.error("rollback call contract tx error.", e);
        return Result.getFailed();
    }
    return Result.getSuccess();
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) VarInt(io.nuls.kernel.utils.VarInt) ArrayList(java.util.ArrayList) IOException(java.io.IOException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) IOException(java.io.IOException) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) Result(io.nuls.kernel.model.Result) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) Transaction(io.nuls.kernel.model.Transaction) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) ContractTokenTransferInfoPo(io.nuls.contract.dto.ContractTokenTransferInfoPo)

Example 2 with CallContractTransaction

use of io.nuls.contract.entity.tx.CallContractTransaction in project nuls by nuls-io.

the class ContractTxServiceImpl method contractCallTx.

/**
 * 创建调用智能合约的交易
 *
 * @param sender          交易创建者
 * @param value           交易附带的货币量
 * @param gasLimit        最大gas消耗
 * @param price           执行合约单价
 * @param contractAddress 合约地址
 * @param methodName      方法名
 * @param methodDesc      方法签名,如果方法名不重复,可以不传
 * @param args            参数列表
 * @param password        账户密码
 * @param remark          备注
 * @return
 */
@Override
public Result contractCallTx(String sender, Na value, Long gasLimit, Long price, String contractAddress, String methodName, String methodDesc, String[][] args, String password, String remark) {
    try {
        AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
        AssertUtil.canNotEmpty(contractAddress, "the contractAddress can not be empty");
        AssertUtil.canNotEmpty(methodName, "the methodName can not be empty");
        if (value == null) {
            value = Na.ZERO;
        }
        if (!ContractUtil.checkPrice(price.longValue())) {
            return Result.getFailed(ContractErrorCode.CONTRACT_MINIMUM_PRICE);
        }
        Result<Account> accountResult = accountService.getAccount(sender);
        if (accountResult.isFailed()) {
            return accountResult;
        }
        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);
            }
        }
        if (!account.isOk()) {
            return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
        }
        byte[] senderBytes = AddressTool.getAddress(sender);
        byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
        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执行数据
        ProgramCall programCall = new ProgramCall();
        programCall.setContractAddress(contractAddressBytes);
        programCall.setSender(senderBytes);
        programCall.setNumber(blockHeight);
        programCall.setMethodName(methodName);
        programCall.setMethodDesc(methodDesc);
        programCall.setArgs(args);
        // 如果方法是不上链的合约调用,同步执行合约代码,不改变状态根,并返回值
        ProgramMethod method;
        if ((method = vmHelper.getMethodInfoByContractAddress(methodName, methodDesc, contractAddressBytes)).isView()) {
            ProgramResult programResult = vmHelper.invokeCustomGasViewMethod(contractAddressBytes, methodName, methodDesc, ContractUtil.twoDimensionalArray(args, method.argsType2Array()));
            // programCall.setValue(BigInteger.ZERO);
            // programCall.setGasLimit(ContractConstant.CONTRACT_CONSTANT_GASLIMIT);
            // programCall.setPrice(ContractConstant.CONTRACT_CONSTANT_PRICE);
            // ProgramExecutor track = programExecutor.begin(prevStateRoot);
            // ProgramResult programResult = track.call(programCall);
            Result result;
            if (!programResult.isSuccess()) {
                Log.error(programResult.getStackTrace());
                result = Result.getFailed(ContractErrorCode.DATA_ERROR);
                result.setMsg(ContractUtil.simplifyErrorMsg(programResult.getErrorMessage()));
                result = checkVmResultAndReturn(programResult.getErrorMessage(), result);
            } else {
                result = Result.getSuccess();
                result.setData(programResult.getResult());
            }
            return result;
        }
        // 创建链上交易,包含智能合约
        programCall.setValue(BigInteger.valueOf(value.getValue()));
        programCall.setPrice(price.longValue());
        programCall.setGasLimit(gasLimit.longValue());
        CallContractTransaction tx = new CallContractTransaction();
        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);
        }
        // 执行VM验证合法性
        ProgramExecutor track = programExecutor.begin(prevStateRoot);
        // 验证合约时跳过Gas验证
        long realGasLimit = programCall.getGasLimit();
        programCall.setGasLimit(MAX_GASLIMIT);
        ProgramResult programResult = track.call(programCall);
        // 执行结果失败时,交易直接返回错误,不上链,不消耗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);
            programCall.setGasLimit(realGasLimit);
            programResult = track.call(programCall);
            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
        CallContractData callContractData = new CallContractData();
        callContractData.setContractAddress(contractAddressBytes);
        callContractData.setSender(senderBytes);
        callContractData.setValue(value.getValue());
        callContractData.setPrice(price.longValue());
        callContractData.setGasLimit(gasLimit.longValue());
        callContractData.setMethodName(methodName);
        callContractData.setMethodDesc(methodDesc);
        if (args != null) {
            callContractData.setArgsCount((byte) args.length);
            callContractData.setArgs(args);
        }
        tx.setTxData(callContractData);
        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);
        // 保存未确认Token转账
        Result<byte[]> unConfirmedTokenTransferResult = this.saveUnConfirmedTokenTransfer(tx, sender, contractAddress, methodName, args);
        if (unConfirmedTokenTransferResult.isFailed()) {
            return unConfirmedTokenTransferResult;
        }
        byte[] infoKey = unConfirmedTokenTransferResult.getData();
        // 保存未确认交易到本地账本
        Result saveResult = accountLedgerService.verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            if (infoKey != null) {
                contractTokenTransferStorageService.deleteTokenTransferInfo(infoKey);
            }
            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);
            if (infoKey != null) {
                contractTokenTransferStorageService.deleteTokenTransferInfo(infoKey);
            }
            return sendResult;
        }
        return Result.getSuccess().setData(tx.getHash().getDigestHex());
    } catch (IOException e) {
        Log.error(e);
        Result result = Result.getFailed(ContractErrorCode.CONTRACT_EXECUTE_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_EXECUTE_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) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException)

Example 3 with CallContractTransaction

use of io.nuls.contract.entity.tx.CallContractTransaction in project nuls by nuls-io.

the class ContractSdkResource method callContractTx.

@POST
@Path("/sdk/call")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "call smart contract transaction")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult callContractTx(@ApiParam(name = "callForm", value = "call smart contract transaction", required = true) CallContractTx callContractTx) {
    if (!AddressTool.validAddress(callContractTx.getSender())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    String contractAddress = callContractTx.getContractAddress();
    if (!AddressTool.validAddress(contractAddress)) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (callContractTx.getGasLimit() < 0 || callContractTx.getPrice() < 0) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (StringUtils.isBlank(callContractTx.getMethodName())) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (callContractTx.getUtxos().isEmpty()) {
        // utxo not null and size not zero.
        return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
    }
    Long gasLimit = callContractTx.getGasLimit();
    Long price = callContractTx.getPrice();
    Na value = Na.valueOf(callContractTx.getValue());
    byte[] senderBytes = AddressTool.getAddress(callContractTx.getSender());
    byte[] contractAddressBytes = AddressTool.getAddress(callContractTx.getContractAddress());
    if (value == null) {
        value = Na.ZERO;
    }
    CallContractTransaction tx = new CallContractTransaction();
    String remark = callContractTx.getRemark();
    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());
    long gasUsed = gasLimit.longValue();
    Na imputedNa = Na.valueOf(LongUtils.mul(gasUsed, price));
    Na totalNa = imputedNa.add(value);
    CallContractData callContractData = new CallContractData();
    callContractData.setContractAddress(contractAddressBytes);
    callContractData.setSender(senderBytes);
    callContractData.setValue(value.getValue());
    callContractData.setPrice(price.longValue());
    callContractData.setGasLimit(gasLimit.longValue());
    callContractData.setMethodName(callContractTx.getMethodName());
    callContractData.setMethodDesc(callContractTx.getMethodDesc());
    /**
     * build args
     */
    Object[] args = callContractTx.getArgs();
    if (args != null) {
        callContractData.setArgsCount((byte) args.length);
        callContractData.setArgs(ContractUtil.twoDimensionalArray(args));
    }
    tx.setTxData(callContractData);
    /**
     * build coin data
     */
    CoinData coinData = new CoinData();
    // transfer to contract address.
    if (value.isGreaterThan(Na.ZERO)) {
        Coin toCoin = new Coin(contractAddressBytes, value);
        coinData.getTo().add(toCoin);
    }
    List<Coin> coinList = ConvertCoinTool.convertCoinList(callContractTx.getUtxos());
    CoinDataResult coinDataResult = CoinDataTool.getCoinData(senderBytes, totalNa, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
    if (!coinDataResult.isEnough()) {
        return RpcClientResult.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
    }
    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, contractAddress);
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 4 with CallContractTransaction

use of io.nuls.contract.entity.tx.CallContractTransaction in project nuls by nuls-io.

the class BlockServiceImpl method contractTransfer.

private void contractTransfer(Transaction tx, List<Transaction> txList) {
    if (tx instanceof CallContractTransaction) {
        CallContractTransaction callTx = (CallContractTransaction) tx;
        ContractResult contractResult = callTx.getContractResult();
        if (contractResult != null) {
            List<ContractTransfer> transfers = contractResult.getTransfers();
            // 合约调用交易存在合约转账(从合约转出)交易,则从全网账本中查出完整交易添加到交易集合中
            if (transfers != null && transfers.size() > 0) {
                for (ContractTransfer transfer : transfers) {
                    Transaction contractTx = ledgerService.getTx(transfer.getHash());
                    if (contractTx != null) {
                        txList.add(contractTx);
                    }
                }
            }
        }
    }
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) ContractTransfer(io.nuls.contract.dto.ContractTransfer) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction)

Example 5 with CallContractTransaction

use of io.nuls.contract.entity.tx.CallContractTransaction in project nuls by nuls-io.

the class ContractTxServiceImpl method transferFee.

@Override
public Result transferFee(String sender, Na value, Long gasLimit, Long price, String contractAddress, String methodName, String methodDesc, String[][] args, String remark) {
    try {
        AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
        AssertUtil.canNotEmpty(contractAddress, "the contractAddress can not be empty");
        AssertUtil.canNotEmpty(methodName, "the methodName can not be empty");
        if (value == null) {
            value = Na.ZERO;
        }
        Result<Account> accountResult = accountService.getAccount(sender);
        if (accountResult.isFailed()) {
            return accountResult;
        }
        byte[] senderBytes = AddressTool.getAddress(sender);
        byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
        BlockHeader blockHeader = NulsContext.getInstance().getBestBlock().getHeader();
        // 当前区块状态根
        byte[] prevStateRoot = ContractUtil.getStateRoot(blockHeader);
        AssertUtil.canNotEmpty(prevStateRoot, "All features of the smart contract are locked.");
        CallContractTransaction tx = new CallContractTransaction();
        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 coinData = new CoinData();
        // 向智能合约账户转账
        if (!Na.ZERO.equals(value)) {
            Coin toCoin = new Coin(contractAddressBytes, value);
            coinData.getTo().add(toCoin);
        }
        long gasUsed = gasLimit.longValue();
        Na imputedGasUsedNa = Na.valueOf(LongUtils.mul(gasUsed, price));
        // 总花费
        Na totalNa = imputedGasUsedNa.add(value);
        // 组装txData
        CallContractData callContractData = new CallContractData();
        callContractData.setContractAddress(contractAddressBytes);
        callContractData.setSender(senderBytes);
        callContractData.setValue(value.getValue());
        callContractData.setPrice(price.longValue());
        callContractData.setGasLimit(gasLimit.longValue());
        callContractData.setMethodName(methodName);
        callContractData.setMethodDesc(methodDesc);
        if (args != null) {
            callContractData.setArgsCount((byte) args.length);
            callContractData.setArgs(args);
        }
        tx.setTxData(callContractData);
        Na fee = accountLedgerService.getTxFee(senderBytes, totalNa, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
        fee = fee.add(imputedGasUsedNa);
        return Result.getSuccess().setData(new Object[] { fee, tx });
    } catch (Exception e) {
        Log.error(e);
        Result result = Result.getFailed(ContractErrorCode.SYS_UNKOWN_EXCEPTION);
        result.setMsg(e.getMessage());
        return result;
    }
}
Also used : Account(io.nuls.account.model.Account) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) 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) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction)

Aggregations

CallContractTransaction (io.nuls.contract.entity.tx.CallContractTransaction)5 ContractResult (io.nuls.contract.dto.ContractResult)4 CallContractData (io.nuls.contract.entity.txdata.CallContractData)4 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)3 IOException (java.io.IOException)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)3 Account (io.nuls.account.model.Account)2 ContractTransferTransaction (io.nuls.contract.entity.tx.ContractTransferTransaction)2 NulsException (io.nuls.kernel.exception.NulsException)2 ContractTokenTransferInfoPo (io.nuls.contract.dto.ContractTokenTransferInfoPo)1 ContractTransfer (io.nuls.contract.dto.ContractTransfer)1 ContractAddressInfoPo (io.nuls.contract.storage.po.ContractAddressInfoPo)1 ECKey (io.nuls.core.tools.crypto.ECKey)1 Result (io.nuls.kernel.model.Result)1 Transaction (io.nuls.kernel.model.Transaction)1 VarInt (io.nuls.kernel.utils.VarInt)1 ValidateResult (io.nuls.kernel.validate.ValidateResult)1 ArrayList (java.util.ArrayList)1 POST (javax.ws.rs.POST)1 Path (javax.ws.rs.Path)1