Search in sources :

Example 1 with TransferTransaction

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

the class AccountLedgerServiceImpl method createTransaction.

@Override
public Result createTransaction(List<Coin> inputs, List<Coin> outputs, byte[] remark) {
    TransferTransaction tx = new TransferTransaction();
    CoinData coinData = new CoinData();
    coinData.setTo(outputs);
    coinData.setFrom(inputs);
    tx.setRemark(remark);
    tx.setCoinData(coinData);
    tx.setTime(TimeService.currentTimeMillis());
    // 计算交易手续费最小值
    int size = tx.size() + P2PHKSignature.SERIALIZE_LENGTH;
    Na minFee = TransactionFeeCalculator.getTransferFee(size);
    // 计算inputs和outputs的差额 ,求手续费
    Na fee = Na.ZERO;
    for (Coin coin : tx.getCoinData().getFrom()) {
        fee = fee.add(coin.getNa());
    }
    for (Coin coin : tx.getCoinData().getTo()) {
        fee = fee.subtract(coin.getNa());
    }
    if (fee.isLessThan(minFee)) {
        return Result.getFailed(LedgerErrorCode.FEE_NOT_RIGHT);
    }
    try {
        String txHex = Hex.encode(tx.serialize());
        return Result.getSuccess().setData(txHex);
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.IO_ERROR);
    }
}
Also used : IOException(java.io.IOException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction)

Example 2 with TransferTransaction

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

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

the class AccountLedgerResource method createTransactionSimple.

@POST
@Path("/transaction/simple")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "创建转账交易(不用计算手续费)", notes = "返回交易Hash,交易对象序列化数组Hex编码,本次交易的输入,输出")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult createTransactionSimple(@ApiParam(name = "form", value = "转账参数(传入该账户拥有的UTXO)", required = true) TransferSimpleForm form) {
    try {
        if (form == null) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (form.getUtxos() == null || form.getUtxos().isEmpty()) {
            return RpcClientResult.getFailed("inputs error");
        }
        if (!AddressTool.validAddress(form.getAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (!AddressTool.validAddress(form.getToAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (form.getAmount() <= 0) {
            return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
        }
        byte[] remarkBytes = new byte[0];
        if (form.getRemark() != null && form.getRemark().length() > 0) {
            try {
                remarkBytes = form.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING);
            } catch (UnsupportedEncodingException e) {
                return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
            }
        }
        byte[] fromBytes = AddressTool.getAddress(form.getAddress());
        byte[] toBytes = AddressTool.getAddress(form.getToAddress());
        Na values = Na.valueOf(form.getAmount());
        TransferTransaction tx = new TransferTransaction();
        tx.setRemark(remarkBytes);
        tx.setTime(TimeService.currentTimeMillis());
        CoinData coinData = new CoinData();
        // 如果为多签地址则以脚本方式存储
        Coin toCoin;
        if (toBytes[2] == NulsContext.P2SH_ADDRESS_TYPE) {
            Script scriptPubkey = SignatureUtil.createOutputScript(toBytes);
            toCoin = new Coin(scriptPubkey.getProgram(), values);
        } else {
            toCoin = new Coin(toBytes, values);
        }
        coinData.getTo().add(toCoin);
        List<Coin> coinList = ConvertCoinTool.convertCoinList(form.getUtxos());
        CoinDataResult coinDataResult = getCoinData(fromBytes, values, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE).toRpcClientResult();
        }
        coinData.setFrom(coinDataResult.getCoinList());
        // 找零的UTXO
        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();
        }
        TransactionCreatedReturnInfo returnInfo = LedgerRpcUtil.makeReturnInfo(tx);
        Map<String, TransactionCreatedReturnInfo> map = new HashMap<>();
        map.put("value", returnInfo);
        return Result.getSuccess().setData(map).toRpcClientResult();
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(AccountLedgerErrorCode.SYS_UNKOWN_EXCEPTION).toRpcClientResult();
    }
}
Also used : Script(io.nuls.kernel.script.Script) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CryptoException(io.nuls.core.tools.crypto.Exception.CryptoException) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 4 with TransferTransaction

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

the class AccountLedgerResource method transferFee.

@GET
@Path("/transfer/fee")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "转账手续费", notes = "result.data: resultJson 返回转账结果")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult transferFee(@BeanParam() TransferFeeForm form) {
    if (form == null) {
        return Result.getFailed(KernelErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (!AddressTool.validAddress(form.getAddress())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (!AddressTool.validAddress(form.getToAddress())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (form.getAmount() <= 0) {
        return Result.getFailed(KernelErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    Na value = Na.valueOf(form.getAmount());
    Result result = accountLedgerService.transferFee(AddressTool.getAddress(form.getAddress()), AddressTool.getAddress(form.getToAddress()), value, form.getRemark(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
    Long fee = null;
    Long maxAmount = null;
    Map<String, Long> map = new HashMap<>();
    if (result.isSuccess()) {
        fee = ((Na) result.getData()).getValue();
        // 如果手续费大于理论最大值,则说明交易过大,需要计算最大交易金额
        long feeMax = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES.multiply(TxMaxSizeValidator.MAX_TX_BYTES).getValue();
        if (fee > feeMax) {
            Transaction tx = new TransferTransaction();
            try {
                tx.setRemark(form.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                Log.error(e);
            }
            tx.setTime(TimeService.currentTimeMillis());
            CoinData coinData = new CoinData();
            Coin toCoin = new Coin(AddressTool.getAddress(form.getToAddress()), value);
            coinData.getTo().add(toCoin);
            tx.setCoinData(coinData);
            Result rs = accountLedgerService.getMaxAmountOfOnce(AddressTool.getAddress(form.getAddress()), tx, TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
            if (rs.isSuccess()) {
                maxAmount = ((Na) rs.getData()).getValue();
            }
        }
        map.put("fee", fee);
        map.put("maxAmount", maxAmount);
        result.setData(map);
    }
    return result.toRpcClientResult();
}
Also used : TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) UnsupportedEncodingException(java.io.UnsupportedEncodingException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 5 with TransferTransaction

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

the class AccountLedgerServiceImpl method transferFee.

@Override
public Result transferFee(byte[] from, byte[] to, Na values, String remark, Na price) {
    Result<Account> accountResult = accountService.getAccount(from);
    if (accountResult.isFailed()) {
        return accountResult;
    }
    if (!accountResult.getData().isOk()) {
        return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
    }
    TransferTransaction tx = new TransferTransaction();
    try {
        tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
    } catch (UnsupportedEncodingException e) {
        return Result.getFailed(LedgerErrorCode.PARAMETER_ERROR);
    }
    tx.setTime(TimeService.currentTimeMillis());
    CoinData coinData = new CoinData();
    Script scriptPubkey = SignatureUtil.createOutputScript(to);
    Coin toCoin = new Coin(scriptPubkey.getProgram(), values);
    coinData.getTo().add(toCoin);
    tx.setCoinData(coinData);
    Na fee = getTxFee(from, values, tx.size() + P2PHKSignature.SERIALIZE_LENGTH, price);
    Result result = Result.getSuccess().setData(fee);
    return result;
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) UnsupportedEncodingException(java.io.UnsupportedEncodingException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) TransactionDataResult(io.nuls.account.ledger.model.TransactionDataResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

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