Search in sources :

Example 31 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult 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 32 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class AliasService method getMultiAliasFee.

/**
 * 获取设置别名交易手续费
 * Gets to set the alias transaction fee
 *
 * @param address
 * @param aliasName
 * @return
 */
public Result<Na> getMultiAliasFee(String address, String aliasName) {
    if (!AddressTool.validAddress(address)) {
        Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
    }
    byte[] addressBytes = AddressTool.getAddress(address);
    try {
        // 创建一笔设置别名的交易
        AliasTransaction tx = new AliasTransaction();
        tx.setTime(TimeService.currentTimeMillis());
        Alias alias = new Alias(addressBytes, aliasName);
        tx.setTxData(alias);
        CoinDataResult coinDataResult = accountLedgerService.getMutilCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
        }
        CoinData coinData = new CoinData();
        coinData.setFrom(coinDataResult.getCoinList());
        Coin change = coinDataResult.getChange();
        if (null != change) {
            // 创建toList
            List<Coin> toList = new ArrayList<>();
            toList.add(change);
            coinData.setTo(toList);
        }
        Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
        coinData.addTo(coin);
        tx.setCoinData(coinData);
        Na fee = TransactionFeeCalculator.getMaxFee(tx.size());
        return Result.getSuccess().setData(fee);
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
    }
}
Also used : AliasTransaction(io.nuls.account.tx.AliasTransaction) Alias(io.nuls.account.model.Alias) ArrayList(java.util.ArrayList) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException)

Example 33 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class AliasService method setMutilAlias.

/**
 * 多签账户设置别名
 * Initiate a transaction to set alias.
 *
 * @param addr      Address of account
 * @param password  password of account
 * @param aliasName the alias to set
 * @return txhash
 */
public Result<String> setMutilAlias(String addr, String signAddr, String aliasName, String password, List<String> pubKeys, int m, String txdata) {
    // 签名账户
    Account account = accountService.getAccount(signAddr).getData();
    if (null == account) {
        return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
    }
    if (account.isEncrypted() && account.isLocked()) {
        if (!account.validatePassword(password)) {
            return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
        }
    }
    try {
        AliasTransaction tx = new AliasTransaction();
        TransactionSignature transactionSignature = new TransactionSignature();
        List<P2PHKSignature> p2PHKSignatures = new ArrayList<>();
        List<Script> scripts = new ArrayList<>();
        byte[] addressBytes = AddressTool.getAddress(addr);
        // 如果txdata为空则表示当前请求为多签发起者调用,需要创建交易
        if (txdata == null || txdata.trim().length() == 0) {
            if (!StringUtils.validAlias(aliasName)) {
                return Result.getFailed(AccountErrorCode.ALIAS_FORMAT_WRONG);
            }
            if (!isAliasUsable(aliasName)) {
                return Result.getFailed(AccountErrorCode.ALIAS_EXIST);
            }
            // 创建一笔设置别名的交易
            tx = new AliasTransaction();
            Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubKeys);
            tx.setTime(TimeService.currentTimeMillis());
            Alias alias = new Alias(addressBytes, aliasName);
            tx.setTxData(alias);
            // 交易签名的长度为m*单个签名长度+赎回脚本长度
            int scriptSignLenth = redeemScript.getProgram().length + m * 72;
            CoinDataResult coinDataResult = accountLedgerService.getMutilCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size() + scriptSignLenth, TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
            if (!coinDataResult.isEnough()) {
                return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
            }
            CoinData coinData = new CoinData();
            coinData.setFrom(coinDataResult.getCoinList());
            Coin change = coinDataResult.getChange();
            if (null != change) {
                // 创建toList
                List<Coin> toList = new ArrayList<>();
                toList.add(change);
                coinData.setTo(toList);
            }
            Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
            coinData.addTo(coin);
            tx.setCoinData(coinData);
            tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
            // 将赎回脚本先存储在签名脚本中
            scripts.add(redeemScript);
            transactionSignature.setScripts(scripts);
        } else // 如果txdata不为空表示多签交易已经创建好了,将交易反序列化出来
        {
            byte[] txByte = Hex.decode(txdata);
            tx.parse(new NulsByteBuffer(txByte));
            transactionSignature.parse(new NulsByteBuffer(tx.getTransactionSignature()));
            p2PHKSignatures = transactionSignature.getP2PHKSignatures();
            scripts = transactionSignature.getScripts();
        }
        // 使用签名账户对交易进行签名
        P2PHKSignature p2PHKSignature = new P2PHKSignature();
        ECKey eckey = account.getEcKey(password);
        p2PHKSignature.setPublicKey(eckey.getPubKey());
        // 用当前交易的hash和账户的私钥账户
        p2PHKSignature.setSignData(accountService.signDigest(tx.getHash().getDigestBytes(), eckey));
        p2PHKSignatures.add(p2PHKSignature);
        Result result = txMutilProcessing(tx, p2PHKSignatures, scripts, transactionSignature, addressBytes);
        return result;
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) AliasTransaction(io.nuls.account.tx.AliasTransaction) ArrayList(java.util.ArrayList) ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Alias(io.nuls.account.model.Alias) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsByteBuffer(io.nuls.kernel.utils.NulsByteBuffer)

Example 34 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class AliasService method setAlias.

/**
 * 设置别名
 * Initiate a transaction to set alias.
 *
 * @param addr      Address of account
 * @param password  password of account
 * @param aliasName the alias to set
 * @return txhash
 */
public Result<String> setAlias(String addr, String aliasName, String password) {
    if (!AddressTool.validAddress(addr)) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
    }
    Account account = accountService.getAccount(addr).getData();
    if (null == account) {
        return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
    }
    if (account.isEncrypted() && account.isLocked()) {
        if (!account.validatePassword(password)) {
            return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
        }
    }
    if (!account.isOk()) {
        return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
    }
    if (StringUtils.isNotBlank(account.getAlias())) {
        return Result.getFailed(AccountErrorCode.ACCOUNT_ALREADY_SET_ALIAS);
    }
    if (!StringUtils.validAlias(aliasName)) {
        return Result.getFailed(AccountErrorCode.ALIAS_FORMAT_WRONG);
    }
    if (!isAliasUsable(aliasName)) {
        return Result.getFailed(AccountErrorCode.ALIAS_EXIST);
    }
    byte[] addressBytes = account.getAddress().getAddressBytes();
    try {
        // 创建一笔设置别名的交易
        AliasTransaction tx = new AliasTransaction();
        tx.setTime(TimeService.currentTimeMillis());
        Alias alias = new Alias(addressBytes, aliasName);
        tx.setTxData(alias);
        CoinDataResult coinDataResult = accountLedgerService.getCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
        }
        CoinData coinData = new CoinData();
        coinData.setFrom(coinDataResult.getCoinList());
        Coin change = coinDataResult.getChange();
        if (null != change) {
            // 创建toList
            List<Coin> toList = new ArrayList<>();
            toList.add(change);
            coinData.setTo(toList);
        }
        Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, AccountConstant.ALIAS_NA, 0);
        coinData.addTo(coin);
        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(account.getAddress().getAddressBytes(), tx, TransactionFeeCalculator.OTHER_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;
        }
        this.transactionService.newTx(tx);
        Result sendResult = this.transactionService.broadcastTx(tx);
        if (sendResult.isFailed()) {
            accountLedgerService.deleteTransaction(tx);
            return sendResult;
        }
        String hash = tx.getHash().getDigestHex();
        return Result.getSuccess().setData(hash);
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) AliasTransaction(io.nuls.account.tx.AliasTransaction) ArrayList(java.util.ArrayList) ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Alias(io.nuls.account.model.Alias) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 35 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class AliasService method getAliasFee.

/**
 * 获取设置别名交易手续费
 * Gets to set the alias transaction fee
 *
 * @param address
 * @param aliasName
 * @return
 */
public Result<Na> getAliasFee(String address, String aliasName) {
    if (!AddressTool.validAddress(address)) {
        Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
    }
    Account account = accountService.getAccount(address).getData();
    if (null == account) {
        return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
    }
    if (!account.isOk()) {
        return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
    }
    byte[] addressBytes = account.getAddress().getAddressBytes();
    try {
        // 创建一笔设置别名的交易
        AliasTransaction tx = new AliasTransaction();
        tx.setTime(TimeService.currentTimeMillis());
        Alias alias = new Alias(addressBytes, aliasName);
        tx.setTxData(alias);
        CoinDataResult coinDataResult = accountLedgerService.getCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
        }
        CoinData coinData = new CoinData();
        coinData.setFrom(coinDataResult.getCoinList());
        Coin change = coinDataResult.getChange();
        if (null != change) {
            // 创建toList
            List<Coin> toList = new ArrayList<>();
            toList.add(change);
            coinData.setTo(toList);
        }
        Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
        coinData.addTo(coin);
        tx.setCoinData(coinData);
        Na fee = TransactionFeeCalculator.getMaxFee(tx.size());
        return Result.getSuccess().setData(fee);
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) AliasTransaction(io.nuls.account.tx.AliasTransaction) Alias(io.nuls.account.model.Alias) ArrayList(java.util.ArrayList) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException)

Aggregations

CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)35 Account (io.nuls.account.model.Account)22 NulsException (io.nuls.kernel.exception.NulsException)22 MultiSigAccount (io.nuls.account.model.MultiSigAccount)20 IOException (java.io.IOException)20 UnsupportedEncodingException (java.io.UnsupportedEncodingException)15 ECKey (io.nuls.core.tools.crypto.ECKey)14 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)10 TransferTransaction (io.nuls.protocol.model.tx.TransferTransaction)8 TransactionDataResult (io.nuls.account.ledger.model.TransactionDataResult)7 AliasTransaction (io.nuls.account.tx.AliasTransaction)7 ValidateResult (io.nuls.kernel.validate.ValidateResult)7 MultipleAddressTransferModel (io.nuls.account.ledger.model.MultipleAddressTransferModel)6 ArrayList (java.util.ArrayList)6 Alias (io.nuls.account.model.Alias)5 NulsByteBuffer (io.nuls.kernel.utils.NulsByteBuffer)5 DataTransaction (io.nuls.protocol.model.tx.DataTransaction)4 LogicData (io.nuls.protocol.model.tx.LogicData)4 AccountConstant (io.nuls.account.constant.AccountConstant)3 AccountErrorCode (io.nuls.account.constant.AccountErrorCode)3