Search in sources :

Example 16 with TransferTransaction

use of io.nuls.protocol.model.tx.TransferTransaction 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 17 with TransferTransaction

use of io.nuls.protocol.model.tx.TransferTransaction in project nuls by nuls-io.

the class AccountLedgerServiceImpl method createTransferTx.

public TransactionDataResult createTransferTx(byte[] address, Na amount, Na price, byte[] to, byte[] remark) {
    TransactionDataResult result = new TransactionDataResult();
    result.setEnough(false);
    TransferTransaction tx = new TransferTransaction();
    tx.setRemark(remark);
    tx.setTime(TimeService.currentTimeMillis());
    CoinData coinData = new CoinData();
    lock.lock();
    try {
        int size = tx.size();
        int signType = 0;
        List<Coin> coinList = balanceManager.getCoinListByAddress(address);
        coinList = coinList.stream().filter(coin1 -> coin1.usable() && !Na.ZERO.equals(coin1.getNa())).sorted(CoinComparator.getInstance()).collect(Collectors.toList());
        if (coinList.isEmpty()) {
            return result;
        }
        List<Coin> coins = new ArrayList<>();
        Na values = Na.ZERO;
        // 累加到足够支付转出额与手续费
        for (int i = 0; i < coinList.size(); i++) {
            Coin coin = coinList.get(i);
            coins.add(coin);
            size += coin.size();
            if (i == 127) {
                size += 1;
            }
            /**
             * 判断是否是脚本验证UTXO
             */
            signType = result.getSignType();
            if (signType != 3) {
                if ((signType & 0x01) == 0 && coin.getTempOwner().length == 23) {
                    result.setSignType((byte) (signType | 0x01));
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                } else if ((signType & 0x02) == 0 && coin.getTempOwner().length != 23) {
                    result.setSignType((byte) (signType | 0x02));
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                }
            }
            values = values.add(coin.getNa());
            if (values.isGreaterOrEquals(amount)) {
                result.setEnough(true);
                break;
            }
        }
        if (!result.isEnough()) {
            return result;
        }
        // 如果为多签地址则以脚本方式存储
        Coin toCoin;
        if (to[2] == NulsContext.P2SH_ADDRESS_TYPE) {
            Script scriptPubkey = SignatureUtil.createOutputScript(to);
            toCoin = new Coin(scriptPubkey.getProgram(), values);
        } else {
            toCoin = new Coin(to, values);
        }
        coinData.getTo().add(toCoin);
        // 如果金额足够,判断是否找零,以及计算手续费
        if (values.isGreaterThan(amount)) {
            Na change = values.subtract(amount);
            Coin changeCoin = new Coin();
            if (address[2] == NulsContext.P2SH_ADDRESS_TYPE) {
                changeCoin.setOwner(SignatureUtil.createOutputScript(address).getProgram());
            } else {
                changeCoin.setOwner(address);
            }
            changeCoin.setNa(change);
            coinData.getTo().add(changeCoin);
        }
        size += coinData.size();
        Na fee = TransactionFeeCalculator.getFee(size, price);
        toCoin.setNa(amount.subtract(fee));
        coinData.setFrom(coins);
        tx.setCoinData(coinData);
        result.setTransaction(tx);
        return result;
    } 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) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction)

Example 18 with TransferTransaction

use of io.nuls.protocol.model.tx.TransferTransaction in project nuls by nuls-io.

the class AccountLedgerServiceImpl method getChangeWholeTxInfoList.

private TransferTransaction getChangeWholeTxInfoList(byte[] address, Account account, String password, Na price) {
    // 这里要重新获取可用余额
    List<Coin> coinList = balanceManager.getCoinListByAddress(address);
    TransferTransaction tx = new TransferTransaction();
    changeWholeLock.lock();
    try {
        tx.setTime(TimeService.currentTimeMillis());
        // 默认coindata中to暂定38字节(一条tocoin)
        int size = tx.size() + 38;
        // 计算目标size,coindata中from的总大小
        int targetSize = TxMaxSizeValidator.MAX_TX_SIZE - size;
        if (coinList.isEmpty()) {
            return null;
        }
        // 从大到小
        Collections.sort(coinList, CoinComparatorDesc.getInstance());
        Na max = Na.ZERO;
        List<Coin> coins = new ArrayList<>();
        byte signType = 0;
        for (int i = 0; i < coinList.size(); i++) {
            Coin coin = coinList.get(i);
            if (!coin.usable()) {
                continue;
            }
            if (coin.getNa().equals(Na.ZERO)) {
                continue;
            }
            size += coin.size();
            if (i == 127) {
                size += 1;
            }
            if (size > targetSize) {
                break;
            }
            coins.add(coin);
            /**
             * 判断是否是脚本验证UTXO
             */
            if (signType != 3) {
                if ((signType & 0x01) == 0 && coin.getTempOwner().length == 23) {
                    signType = (byte) (signType | 0x01);
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                } else if ((signType & 0x02) == 0 && coin.getTempOwner().length != 23) {
                    signType = (byte) (signType | 0x02);
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                }
            }
            max = max.add(coin.getNa());
        }
        Na fee = TransactionFeeCalculator.getFee(size, price);
        max = max.subtract(fee);
        CoinData coinData = new CoinData();
        Coin toCoin = new Coin(address, max);
        coinData.getTo().add(toCoin);
        coinData.setFrom(coins);
        tx.setCoinData(coinData);
        // 一定要交易组装完才能setHash
        tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
        // 生成签名
        List<ECKey> signEckeys = new ArrayList<>();
        List<ECKey> scriptEckeys = new ArrayList<>();
        ECKey eckey = account.getEcKey(password);
        // 如果最后一位为1则表示该交易包含普通签名
        if ((signType & 0x01) == 0x01) {
            signEckeys.add(eckey);
        }
        // 如果倒数第二位位为1则表示该交易包含脚本签名
        if ((signType & 0x02) == 0x02) {
            scriptEckeys.add(eckey);
        }
        SignatureUtil.createTransactionSignture(tx, scriptEckeys, signEckeys);
        return tx;
    } catch (RuntimeException | IOException | NulsException e) {
        Log.error(e);
        return null;
    } finally {
        changeWholeLock.unlock();
    }
}
Also used : ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) NulsException(io.nuls.kernel.exception.NulsException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction)

Example 19 with TransferTransaction

use of io.nuls.protocol.model.tx.TransferTransaction in project nuls by nuls-io.

the class AccountLedgerServiceImpl method changeWhole.

@Override
public Result changeWhole(byte[] address, String password, Na price) {
    try {
        Result<Account> accountResult = accountService.getAccount(address);
        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);
            }
        }
        // 检查to是否为合约地址,如果是合约地址,则返回错误
        if (contractService.isContractAddress(address)) {
            return Result.getFailed(ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER);
        }
        TransferTransaction tx = null;
        boolean flag = true;
        while (flag) {
            tx = getChangeWholeTxInfoList(address, account, password, price);
            // 保存未确认交易到本地账户
            if (null != tx) {
                Result saveResult = verifyAndSaveUnconfirmedTransaction(tx);
                if (saveResult.isFailed()) {
                    if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                        // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                        Result rs = getMaxAmountOfOnce(address, 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;
                }
                // 可用总额
                Result available = getAvailableTotalUTXO(address);
                Map<String, Object> map = (Map<String, Object>) available.getData();
                int size = (int) map.get("size");
                if (size < AccountConstant.MIM_COUNT) {
                    // 小于20就停止
                    flag = false;
                }
            } else {
                flag = false;
            }
        }
        return Result.getSuccess().setData(tx.getHash().getDigestHex());
    } catch (Exception e) {
        Log.error(e);
        Log.error("零钱换整错误");
        return Result.getFailed();
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 20 with TransferTransaction

use of io.nuls.protocol.model.tx.TransferTransaction in project nuls by nuls-io.

the class AccountLedgerServiceImpl method estimateFee.

@Override
public Result estimateFee(byte[] address, Na price) {
    if (null == price) {
        throw new NulsRuntimeException(KernelErrorCode.PARAMETER_ERROR);
    }
    Transaction tx = new TransferTransaction();
    tx.setTime(TimeService.currentTimeMillis());
    lock.lock();
    try {
        // 获取这个地址的所有coin的总大小
        List<Coin> coinList = balanceManager.getCoinListByAddress(address);
        if (coinList.isEmpty()) {
            // 没有可用余额
            return Result.getFailed(TransactionErrorCode.DATA_ERROR);
        }
        tx.setCoinData(null);
        // 默认coindata中to为38 +备注+签名
        int txSize = tx.size() + 38 + TxRemarkValidator.MAX_REMARK_LEN;
        int targetSize = TxMaxSizeValidator.MAX_TX_SIZE - txSize;
        Collections.sort(coinList, CoinComparatorDesc.getInstance());
        int size = tx.size() + 38;
        // 将所有余额从大到小排序后,累计未花费的余额
        byte signType = 0;
        int txNum = 1;
        for (int i = 0; i < coinList.size(); i++) {
            Coin coin = coinList.get(i);
            if (!coin.usable()) {
                continue;
            }
            if (coin.getNa().equals(Na.ZERO)) {
                continue;
            }
            size += coin.size();
            if (i == 127) {
                size += 1;
            }
            /**
             * 判断是否是脚本验证UTXO
             */
            if (signType != 3) {
                if ((signType & 0x01) == 0 && coin.getTempOwner().length == 23) {
                    signType = (byte) (signType | 0x01);
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                } else if ((signType & 0x02) == 0 && coin.getTempOwner().length != 23) {
                    signType = (byte) (signType | 0x02);
                    size += P2PHKSignature.SERIALIZE_LENGTH;
                }
            }
            if (size > targetSize * txNum) {
                // 大于一个tx的size 所以需要另一个tx装
                size += txSize;
                txNum++;
                signType = 0;
            }
        }
        Na fee = TransactionFeeCalculator.getFee(size, price);
        return Result.getSuccess().setData(fee);
    } catch (Exception e) {
        return Result.getFailed(TransactionErrorCode.DATA_ERROR);
    } finally {
        lock.unlock();
    }
}
Also used : TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) DataTransaction(io.nuls.protocol.model.tx.DataTransaction) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException)

Aggregations

TransferTransaction (io.nuls.protocol.model.tx.TransferTransaction)22 NulsException (io.nuls.kernel.exception.NulsException)11 IOException (java.io.IOException)11 UnsupportedEncodingException (java.io.UnsupportedEncodingException)10 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)9 ECKey (io.nuls.core.tools.crypto.ECKey)8 ArrayList (java.util.ArrayList)8 Account (io.nuls.account.model.Account)7 MultiSigAccount (io.nuls.account.model.MultiSigAccount)7 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)7 ValidateResult (io.nuls.kernel.validate.ValidateResult)7 TransactionDataResult (io.nuls.account.ledger.model.TransactionDataResult)6 MultipleAddressTransferModel (io.nuls.account.ledger.model.MultipleAddressTransferModel)4 NulsDigestData (io.nuls.kernel.model.NulsDigestData)4 Transaction (io.nuls.kernel.model.Transaction)4 Script (io.nuls.kernel.script.Script)4 Test (org.junit.Test)4 CryptoException (io.nuls.core.tools.crypto.Exception.CryptoException)2 Coin (io.nuls.kernel.model.Coin)2 CoinData (io.nuls.kernel.model.CoinData)2