Search in sources :

Example 1 with MultipleAddressTransferModel

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

the class AccountLedgerServiceImpl method multipleAddressTransfer.

@Override
public Result multipleAddressTransfer(Set<String> addressSet, List<MultipleAddressTransferModel> fromList, List<MultipleAddressTransferModel> toList, Na amount, String remark, Na price) {
    try {
        for (MultipleAddressTransferModel from : fromList) {
            Result<Account> accountResult = accountService.getAccount(from.getAddress());
            if (accountResult.isFailed()) {
                return accountResult;
            }
            Account account = accountResult.getData();
            if (account.isEncrypted() && account.isLocked()) {
                AssertUtil.canNotEmpty(from.getPassword(), "the password can not be empty");
                if (!account.validatePassword(from.getPassword())) {
                    Result result = Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
                    result.setMsg(result.getErrorCode().getMsg() + ",address :" + AddressTool.getStringAddressByBytes(from.getAddress()));
                    return result;
                }
            }
        }
        for (MultipleAddressTransferModel to : toList) {
            // 检查to是否为合约地址,如果是合约地址,则返回错误
            if (contractService.isContractAddress(to.getAddress())) {
                return Result.getFailed(ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER);
            }
        }
        TransferTransaction tx = new TransferTransaction();
        if (StringUtils.isNotBlank(remark)) {
            try {
                tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                Log.error(e);
            }
        }
        tx.setTime(TimeService.currentTimeMillis());
        CoinData coinData = new CoinData();
        for (MultipleAddressTransferModel to : toList) {
            // 如果为多签地址
            Coin toCoin = null;
            if (to.getAddress()[2] == 3) {
                Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
                toCoin = new Coin(scriptPubkey.getProgram(), Na.valueOf(to.getAmount()));
            } else {
                toCoin = new Coin(to.getAddress(), Na.valueOf(to.getAmount()));
            }
            coinData.getTo().add(toCoin);
        }
        if (price == null) {
            price = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES;
        }
        CoinDataResult coinDataResult = getCoinDataMultipleAdresses(fromList, amount, tx.size() + coinData.size() + addressSet.size() * P2PHKSignature.SERIALIZE_LENGTH, price);
        // 从多个地址中获取币 from
        List<Coin> fromCoinList = new ArrayList<>();
        List<Coin> changeCoinList = new ArrayList<>();
        if (!coinDataResult.isEnough()) {
            // 验证utxo是否足够
            return Result.getFailed(AccountLedgerErrorCode.INSUFFICIENT_BALANCE);
        }
        // 把每个地址获取的币放到list里面
        fromCoinList.addAll(coinDataResult.getCoinList());
        if (coinDataResult.getChange() != null) {
            changeCoinList.add(coinDataResult.getChange());
        }
        // 每个地址from获取的utxo list
        coinData.setFrom(fromCoinList);
        // 找零钱
        coinData.getTo().addAll(changeCoinList);
        tx.setCoinData(coinData);
        tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
        // 生成签名
        List<ECKey> signEckeys = new ArrayList<>();
        List<ECKey> scriptEckeys = new ArrayList<>();
        for (int index = 0; index < fromList.size(); index++) {
            Result<Account> accountResult = accountService.getAccount(fromList.get(index).getAddress());
            Account account = accountResult.getData();
            // 用于生成ECKey
            ECKey ecKey = account.getEcKey(fromList.get(index).getPassword());
            // 如果最后一位为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 = verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            for (MultipleAddressTransferModel from : fromList) {
                if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                    // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                    Na maxAmount = getMaxAmountOfOnce(from.getAddress(), tx, price).getData();
                    Result 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()) {
            this.deleteTransaction(tx);
            return sendResult;
        }
        return Result.getSuccess().setData(tx.getHash().getDigestHex());
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.IO_ERROR);
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(e.getErrorCode());
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) MultipleAddressTransferModel(io.nuls.account.ledger.model.MultipleAddressTransferModel) UnsupportedEncodingException(java.io.UnsupportedEncodingException) ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsException(io.nuls.kernel.exception.NulsException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 2 with MultipleAddressTransferModel

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

the class AccountLedgerResource method multipleAddressTransfer.

@POST
@Path("/multipleAddressTransfer")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "多地址转账", notes = "result.data: resultJson 返回转账结果")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult multipleAddressTransfer(@ApiParam(name = "form", value = "创建多账户转账交易", required = true) MulitpleTransactionForm form) {
    if (NulsContext.MAIN_NET_VERSION <= 1) {
        return Result.getFailed(KernelErrorCode.VERSION_TOO_LOW).toRpcClientResult();
    }
    List<MultipleAddressTransferModel> fromModelList = new ArrayList<>();
    List<MultipleAddressTransferModel> toModelList = new ArrayList<>();
    if (form.getInputs() == null || form.getOutputs() == null) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    Set<String> addressSet = new HashSet<>();
    for (MulipleTxFromDto from : form.getInputs()) {
        MultipleAddressTransferModel model = new MultipleAddressTransferModel();
        if (!AddressTool.validAddress(from.getAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        model.setAddress(AddressTool.getAddress(from.getAddress()));
        model.setPassword(from.getPassword());
        fromModelList.add(model);
        addressSet.add(from.getAddress());
    }
    Long toTotal = 0L;
    for (MultipleTxToDto to : form.getOutputs()) {
        MultipleAddressTransferModel model = new MultipleAddressTransferModel();
        if (!AddressTool.validAddress(to.getToAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        model.setAddress(AddressTool.getAddress(to.getToAddress()));
        model.setAmount(to.getAmount());
        toModelList.add(model);
        toTotal += to.getAmount();
    }
    if (toTotal < 0) {
        return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    Result result = accountLedgerService.multipleAddressTransfer(addressSet, fromModelList, toModelList, Na.valueOf(toTotal), form.getRemark(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
    if (result.isSuccess()) {
        Map<String, String> map = new HashMap<>();
        map.put("value", (String) result.getData());
        result.setData(map);
    }
    return result.toRpcClientResult();
}
Also used : MultipleAddressTransferModel(io.nuls.account.ledger.model.MultipleAddressTransferModel) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 3 with MultipleAddressTransferModel

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

the class AccountLedgerServiceImpl method transferP2SH.

/**
 * A transfers NULS to B   多签交易
 *
 * @param fromAddr address of A
 * @param signAddr address of B
 * @param values   NULS amount
 * @param password password of A
 * @param remark   remarks of transaction
 * @param price    Unit price of fee
 * @param pubkeys  公钥列表
 * @param m        至少需要签名验证通过
 * @return Result
 */
@Override
public Result transferP2SH(byte[] fromAddr, byte[] signAddr, List<MultipleAddressTransferModel> outputs, Na values, String password, String remark, Na price, List<String> pubkeys, int m, String txdata) {
    try {
        Result<Account> accountResult = accountService.getAccount(signAddr);
        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);
        }
        TransferTransaction tx = new TransferTransaction();
        TransactionSignature transactionSignature = new TransactionSignature();
        List<P2PHKSignature> p2PHKSignatures = new ArrayList<>();
        List<Script> scripts = new ArrayList<>();
        // 如果txdata为空则表示当前请求为多签发起者调用,需要创建交易
        if (txdata == null || txdata.trim().length() == 0) {
            if (StringUtils.isNotBlank(remark)) {
                try {
                    tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
                } catch (UnsupportedEncodingException e) {
                    Log.error(e);
                }
            }
            Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubkeys);
            tx.setTime(TimeService.currentTimeMillis());
            CoinData coinData = new CoinData();
            for (MultipleAddressTransferModel to : outputs) {
                // 如果为多签地址
                Coin toCoin = null;
                if (to.getAddress()[2] == NulsContext.P2SH_ADDRESS_TYPE) {
                    Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
                    toCoin = new Coin(scriptPubkey.getProgram(), Na.valueOf(to.getAmount()));
                } else {
                    toCoin = new Coin(to.getAddress(), Na.valueOf(to.getAmount()));
                }
                coinData.getTo().add(toCoin);
            }
            if (price == null) {
                price = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES;
            }
            // 交易签名的长度为m*单个签名长度+赎回脚本长度
            int scriptSignLenth = redeemScript.getProgram().length + m * 72;
            CoinDataResult coinDataResult = getMutilCoinData(fromAddr, values, tx.size() + coinData.size() + scriptSignLenth, price);
            if (!coinDataResult.isEnough()) {
                return Result.getFailed(AccountLedgerErrorCode.INSUFFICIENT_BALANCE);
            }
            coinData.setFrom(coinDataResult.getCoinList());
            if (coinDataResult.getChange() != null) {
                coinData.getTo().add(coinDataResult.getChange());
            }
            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);
        // 当已签名数等于M则自动广播该交易
        if (p2PHKSignatures.size() == SignatureUtil.getM(scripts.get(0))) {
            // 将交易中的签名数据P2PHKSignatures按规则排序
            Collections.sort(p2PHKSignatures, P2PHKSignature.PUBKEY_COMPARATOR);
            // 将排序后的P2PHKSignatures的签名数据取出和赎回脚本结合生成解锁脚本
            List<byte[]> signatures = new ArrayList<>();
            for (P2PHKSignature p2PHKSignatureTemp : p2PHKSignatures) {
                signatures.add(p2PHKSignatureTemp.getSignData().getSignBytes());
            }
            transactionSignature.setP2PHKSignatures(null);
            Script scriptSign = ScriptBuilder.createNulsP2SHMultiSigInputScript(signatures, scripts.get(0));
            transactionSignature.getScripts().clear();
            transactionSignature.getScripts().add(scriptSign);
            tx.setTransactionSignature(transactionSignature.serialize());
            // 保存未确认交易到本地账户
            Result saveResult = verifyAndSaveUnconfirmedTransaction(tx);
            if (saveResult.isFailed()) {
                if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                    // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                    Result rs = getMaxAmountOfOnce(fromAddr, tx, price);
                    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()) {
                this.deleteTransaction(tx);
                return sendResult;
            }
            return Result.getSuccess().setData(tx.getHash().getDigestHex());
        } else // 如果签名数还没达到,则返回交易
        {
            transactionSignature.setP2PHKSignatures(p2PHKSignatures);
            tx.setTransactionSignature(transactionSignature.serialize());
            return Result.getSuccess().setData(Hex.encode(tx.serialize()));
        }
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.IO_ERROR);
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(e.getErrorCode());
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) MultipleAddressTransferModel(io.nuls.account.ledger.model.MultipleAddressTransferModel) UnsupportedEncodingException(java.io.UnsupportedEncodingException) ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsException(io.nuls.kernel.exception.NulsException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) NulsByteBuffer(io.nuls.kernel.utils.NulsByteBuffer)

Example 4 with MultipleAddressTransferModel

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

the class AccountLedgerServiceImpl method createP2shTransfer.

/**
 * A transfers NULS to B   多签交易
 *
 * @param fromAddr 输入地址
 * @param signAddr 签名地址
 * @param outputs  输出地址
 * @param password password of A
 * @param remark   remarks of transaction
 * @return Result
 */
@Override
public Result createP2shTransfer(String fromAddr, String signAddr, List<MultipleAddressTransferModel> outputs, String password, String remark) {
    try {
        Result<Account> accountResult = accountService.getAccount(signAddr);
        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);
            }
        }
        TransferTransaction tx = new TransferTransaction();
        TransactionSignature transactionSignature = new TransactionSignature();
        List<Script> scripts = new ArrayList<>();
        Result<MultiSigAccount> result = accountService.getMultiSigAccount(fromAddr);
        MultiSigAccount multiSigAccount = result.getData();
        // 验证签名账户是否属于多签账户,如果不是多签账户下的地址则提示错误
        if (!AddressTool.validSignAddress(multiSigAccount.getPubKeyList(), account.getPubKey())) {
            return Result.getFailed(AccountErrorCode.SIGN_ADDRESS_NOT_MATCH);
        }
        Script redeemScript = getRedeemScript(multiSigAccount);
        if (redeemScript == null) {
            return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
        }
        tx.setTime(TimeService.currentTimeMillis());
        if (StringUtils.isNotBlank(remark)) {
            try {
                tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                Log.error(e);
            }
        }
        CoinData coinData = new CoinData();
        Na values = Na.ZERO;
        for (MultipleAddressTransferModel to : outputs) {
            // 如果为多签地址
            Coin toCoin = null;
            values = values.add(Na.valueOf(to.getAmount()));
            if (to.getAddress()[2] == NulsContext.P2SH_ADDRESS_TYPE) {
                Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
                toCoin = new Coin(scriptPubkey.getProgram(), Na.valueOf(to.getAmount()));
            } else {
                toCoin = new Coin(to.getAddress(), Na.valueOf(to.getAmount()));
            }
            coinData.getTo().add(toCoin);
        }
        // 交易签名的长度为m*单个签名长度+赎回脚本长度
        int scriptSignLenth = redeemScript.getProgram().length + ((int) multiSigAccount.getM()) * 72;
        CoinDataResult coinDataResult = getMutilCoinData(AddressTool.getAddress(fromAddr), values, tx.size() + coinData.size() + scriptSignLenth, TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(AccountLedgerErrorCode.INSUFFICIENT_BALANCE);
        }
        coinData.setFrom(coinDataResult.getCoinList());
        if (coinDataResult.getChange() != null) {
            coinData.getTo().add(coinDataResult.getChange());
        }
        tx.setCoinData(coinData);
        tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
        // 将赎回脚本先存储在签名脚本中
        scripts.add(redeemScript);
        transactionSignature.setScripts(scripts);
        return txMultiProcess(tx, transactionSignature, account, password);
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.IO_ERROR);
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(e.getErrorCode());
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
    }
}
Also used : MultiSigAccount(io.nuls.account.model.MultiSigAccount) Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) MultipleAddressTransferModel(io.nuls.account.ledger.model.MultipleAddressTransferModel) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 5 with MultipleAddressTransferModel

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

the class AccountLedgerServiceImpl method getCoinDataMultipleAdresses.

private CoinDataResult getCoinDataMultipleAdresses(List<MultipleAddressTransferModel> fromList, Na amount, int size, Na price) {
    // 获取多个地址的utxo排序
    List<Coin> coinListUTXO = new ArrayList<>();
    for (int j = 0; j < fromList.size(); j++) {
        byte[] address = fromList.get(j).getAddress();
        List<Coin> coinList = balanceManager.getCoinListByAddress(address);
        coinListUTXO.addAll(coinList);
    }
    if (null == price) {
        throw new NulsRuntimeException(KernelErrorCode.PARAMETER_ERROR);
    }
    lock.lock();
    try {
        CoinDataResult coinDataResult = new CoinDataResult();
        coinDataResult.setEnough(false);
        coinListUTXO = coinListUTXO.stream().filter(coin1 -> coin1.usable() && !Na.ZERO.equals(coin1.getNa())).sorted(CoinComparator.getInstance()).collect(Collectors.toList());
        if (coinListUTXO.isEmpty()) {
            return coinDataResult;
        }
        List<Coin> coins = new ArrayList<>();
        Na values = Na.ZERO;
        // 累加到足够支付转出额与手续费
        // 需要找零的地址,找零是找给最后一个utxo的账户
        byte[] changeAddress = null;
        for (int i = 0; i < coinListUTXO.size(); i++) {
            Coin coin = coinListUTXO.get(i);
            coins.add(coin);
            size += coin.size();
            if (i == 127) {
                size += 1;
            }
            // 每次累加一条未花费余额时,需要重新计算手续费
            Na fee = TransactionFeeCalculator.getFee(size, price);
            values = values.add(coin.getNa());
            /**
             * 判断是否是脚本验证UTXO
             */
            int signType = coinDataResult.getSignType();
            if (signType != 3) {
                if ((signType & 0x01) == 0 && coin.getTempOwner().length == 23) {
                    coinDataResult.setSignType((byte) (signType | 0x01));
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                } else if ((signType & 0x02) == 0 && coin.getTempOwner().length != 23) {
                    coinDataResult.setSignType((byte) (signType | 0x02));
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                }
            }
            // 需要判断是否找零,如果有找零,则需要重新计算手续费
            if (values.isGreaterThan(amount.add(fee))) {
                changeAddress = coin.getTempOwner();
                Na change = values.subtract(amount.add(fee));
                Coin changeCoin = new Coin();
                if (changeAddress[2] == NulsContext.P2SH_ADDRESS_TYPE) {
                    changeCoin.setOwner(SignatureUtil.createOutputScript(changeAddress).getProgram());
                } else {
                    changeCoin.setOwner(changeAddress);
                }
                changeCoin.setNa(change);
                fee = TransactionFeeCalculator.getFee(size + changeCoin.size(), price);
                if (values.isLessThan(amount.add(fee))) {
                    continue;
                }
                changeCoin.setNa(values.subtract(amount.add(fee)));
                if (!changeCoin.getNa().equals(Na.ZERO)) {
                    coinDataResult.setChange(changeCoin);
                }
            }
            coinDataResult.setFee(fee);
            if (values.isGreaterOrEquals(amount.add(fee))) {
                coinDataResult.setEnough(true);
                coinDataResult.setCoinList(coins);
                break;
            }
        }
        return coinDataResult;
    } finally {
        lock.unlock();
    }
}
Also used : Account(io.nuls.account.model.Account) AddressTool(io.nuls.kernel.utils.AddressTool) BlockService(io.nuls.protocol.service.BlockService) ECKey(io.nuls.core.tools.crypto.ECKey) StringUtils(io.nuls.core.tools.str.StringUtils) Service(io.nuls.kernel.lite.annotation.Service) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) InitializingBean(io.nuls.kernel.lite.core.bean.InitializingBean) LogicData(io.nuls.protocol.model.tx.LogicData) NulsContext(io.nuls.kernel.context.NulsContext) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) AccountLedgerErrorCode(io.nuls.account.ledger.constant.AccountLedgerErrorCode) UnconfirmedTransactionStorageService(io.nuls.account.ledger.storage.service.UnconfirmedTransactionStorageService) CoinDataTool(io.nuls.account.ledger.util.CoinDataTool) TransactionService(io.nuls.protocol.service.TransactionService) MultiSigAccount(io.nuls.account.model.MultiSigAccount) Collectors(java.util.stream.Collectors) AccountService(io.nuls.account.service.AccountService) MultipleAddressTransferModel(io.nuls.account.ledger.model.MultipleAddressTransferModel) NulsException(io.nuls.kernel.exception.NulsException) Autowired(io.nuls.kernel.lite.annotation.Autowired) TransactionManager(io.nuls.kernel.utils.TransactionManager) TxMaxSizeValidator(io.nuls.protocol.model.validator.TxMaxSizeValidator) UnsupportedEncodingException(java.io.UnsupportedEncodingException) TransactionInfoService(io.nuls.account.ledger.base.service.TransactionInfoService) LedgerService(io.nuls.ledger.service.LedgerService) java.util(java.util) TimeService(io.nuls.kernel.func.TimeService) NulsByteBuffer(io.nuls.kernel.utils.NulsByteBuffer) AccountLedgerService(io.nuls.account.ledger.service.AccountLedgerService) io.nuls.kernel.script(io.nuls.kernel.script) TransactionInfoPo(io.nuls.account.ledger.storage.po.TransactionInfoPo) io.nuls.kernel.model(io.nuls.kernel.model) ValidateResult(io.nuls.kernel.validate.ValidateResult) AccountLegerUtils(io.nuls.account.ledger.base.util.AccountLegerUtils) ContractErrorCode(io.nuls.contract.constant.ContractErrorCode) AccountConstant(io.nuls.account.constant.AccountConstant) AccountErrorCode(io.nuls.account.constant.AccountErrorCode) NulsConstant(io.nuls.kernel.constant.NulsConstant) TransactionFeeCalculator(io.nuls.kernel.utils.TransactionFeeCalculator) AssertUtil(io.nuls.core.tools.param.AssertUtil) DataTransaction(io.nuls.protocol.model.tx.DataTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) CoinComparatorDesc(io.nuls.account.ledger.base.util.CoinComparatorDesc) UtxoAccountsBalance(io.nuls.utxo.accounts.model.UtxoAccountsBalance) KernelErrorCode(io.nuls.kernel.constant.KernelErrorCode) TransactionErrorCode(io.nuls.kernel.constant.TransactionErrorCode) ReentrantLock(java.util.concurrent.locks.ReentrantLock) CoinComparator(io.nuls.account.ledger.base.util.CoinComparator) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) TransactionInfo(io.nuls.account.ledger.model.TransactionInfo) NulsConfig(io.nuls.kernel.cfg.NulsConfig) UtxoAccountsBalanceService(io.nuls.utxo.accounts.service.UtxoAccountsBalanceService) IOException(java.io.IOException) TxRemarkValidator(io.nuls.protocol.model.validator.TxRemarkValidator) Log(io.nuls.core.tools.log.Log) BalanceManager(io.nuls.account.ledger.base.manager.BalanceManager) ContractService(io.nuls.contract.service.ContractService) Hex(io.nuls.core.tools.crypto.Hex) LedgerUtil(io.nuls.ledger.util.LedgerUtil) Lock(java.util.concurrent.locks.Lock) LedgerErrorCode(io.nuls.ledger.constant.LedgerErrorCode) LocalUtxoService(io.nuls.account.ledger.base.service.LocalUtxoService) Balance(io.nuls.account.model.Balance) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Aggregations

CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)6 MultipleAddressTransferModel (io.nuls.account.ledger.model.MultipleAddressTransferModel)6 ValidateResult (io.nuls.kernel.validate.ValidateResult)5 Account (io.nuls.account.model.Account)4 MultiSigAccount (io.nuls.account.model.MultiSigAccount)4 NulsException (io.nuls.kernel.exception.NulsException)4 TransferTransaction (io.nuls.protocol.model.tx.TransferTransaction)4 IOException (java.io.IOException)4 UnsupportedEncodingException (java.io.UnsupportedEncodingException)4 TransactionDataResult (io.nuls.account.ledger.model.TransactionDataResult)3 ECKey (io.nuls.core.tools.crypto.ECKey)3 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)2 NulsByteBuffer (io.nuls.kernel.utils.NulsByteBuffer)2 AccountConstant (io.nuls.account.constant.AccountConstant)1 AccountErrorCode (io.nuls.account.constant.AccountErrorCode)1 BalanceManager (io.nuls.account.ledger.base.manager.BalanceManager)1 LocalUtxoService (io.nuls.account.ledger.base.service.LocalUtxoService)1 TransactionInfoService (io.nuls.account.ledger.base.service.TransactionInfoService)1 AccountLegerUtils (io.nuls.account.ledger.base.util.AccountLegerUtils)1 CoinComparator (io.nuls.account.ledger.base.util.CoinComparator)1