Search in sources :

Example 26 with CoinDataResult

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

the class AccountLedgerServiceImpl method dapp.

@Override
public Result dapp(byte[] from, String password, byte[] data, byte[] remark) {
    Result<Account> accountResult = accountService.getAccount(from);
    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);
        }
    }
    DataTransaction tx = new DataTransaction();
    tx.setRemark(remark);
    tx.setTime(TimeService.currentTimeMillis());
    LogicData logicData = new LogicData(data);
    tx.setTxData(logicData);
    CoinData coinData = new CoinData();
    try {
        CoinDataResult coinDataResult = getCoinData(from, Na.ZERO, tx.size() + coinData.size(), 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()));
        // 生成签名
        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 = verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                Result rs = getMaxAmountOfOnce(from, 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()) {
            this.deleteTransaction(tx);
            return sendResult;
        }
        return Result.getSuccess().setData(tx.getHash().getDigestHex());
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(e.getErrorCode());
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.IO_ERROR);
    }
}
Also used : Account(io.nuls.account.model.Account) MultiSigAccount(io.nuls.account.model.MultiSigAccount) 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) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) LogicData(io.nuls.protocol.model.tx.LogicData) DataTransaction(io.nuls.protocol.model.tx.DataTransaction)

Example 27 with CoinDataResult

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

the class AccountLedgerServiceImpl method transfer.

@Override
public Result transfer(byte[] from, byte[] to, Na values, String password, byte[] remark, Na price) {
    try {
        if (NulsContext.WALLET_STATUS == NulsConstant.SYNCHING) {
            return Result.getFailed(KernelErrorCode.WALLET_STATUS_SYNCHING);
        } else if (NulsContext.WALLET_STATUS == NulsConstant.ROLLBACK) {
            return Result.getFailed(KernelErrorCode.WALLET_STATUS_ROLLBACK);
        }
        Result<Account> accountResult = accountService.getAccount(from);
        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);
        }
        // 检查to是否为合约地址,如果是合约地址,则返回错误
        if (contractService.isContractAddress(to)) {
            return Result.getFailed(ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER);
        }
        TransferTransaction tx = new TransferTransaction();
        tx.setRemark(remark);
        tx.setTime(TimeService.currentTimeMillis());
        CoinData coinData = new CoinData();
        // 如果为多签地址则以脚本方式存储
        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 (price == null) {
            price = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES;
        }
        CoinDataResult coinDataResult = getCoinData(from, values, tx.size() + coinData.size(), 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()));
        // 生成签名
        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 = verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
                // 重新算一次交易(不超出最大交易数据大小下)的最大金额
                Result rs = getMaxAmountOfOnce(from, 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;
        }
        // transactionService.newTx(tx);
        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) 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 28 with CoinDataResult

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

Example 29 with CoinDataResult

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

the class AccountLedgerServiceImpl method getMutilCoinData.

@Override
public CoinDataResult getMutilCoinData(byte[] address, Na amount, int size, Na price) {
    if (null == price) {
        throw new NulsRuntimeException(KernelErrorCode.PARAMETER_ERROR);
    }
    lock.lock();
    try {
        CoinDataResult coinDataResult = new CoinDataResult();
        coinDataResult.setEnough(false);
        List<Coin> coinList = ledgerService.getAllUtxo(address);
        coinList = coinList.stream().filter(coin1 -> coin1.usable() && !Na.ZERO.equals(coin1.getNa())).sorted(CoinComparator.getInstance()).collect(Collectors.toList());
        if (coinList.isEmpty()) {
            return coinDataResult;
        }
        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;
            }
            // 每次累加一条未花费余额时,需要重新计算手续费
            Na fee = TransactionFeeCalculator.getFee(size, price);
            values = values.add(coin.getNa());
            // 需要判断是否找零,如果有找零,则需要重新计算手续费
            if (values.isGreaterThan(amount.add(fee))) {
                Na change = values.subtract(amount.add(fee));
                Coin changeCoin = new Coin();
                changeCoin.setOwner(SignatureUtil.createOutputScript(address).getProgram());
                // changeCoin.setOwner(address);
                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)

Example 30 with CoinDataResult

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

the class ContractTxServiceImpl method contractDeleteTx.

/**
 * 创建删除智能合约的交易
 *
 * @param sender          交易创建者
 * @param contractAddress 合约地址
 * @param password        账户密码
 * @param remark          备注
 * @return
 */
@Override
public Result contractDeleteTx(String sender, String contractAddress, String password, String remark) {
    try {
        AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
        AssertUtil.canNotEmpty(contractAddress, "the contractAddress can not be empty");
        byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
        Result<ContractAddressInfoPo> contractAddressInfoPoResult = contractAddressStorageService.getContractAddressInfo(contractAddressBytes);
        if (contractAddressInfoPoResult.isFailed()) {
            return contractAddressInfoPoResult;
        }
        ContractAddressInfoPo contractAddressInfoPo = contractAddressInfoPoResult.getData();
        if (contractAddressInfoPo == null) {
            return Result.getFailed(ContractErrorCode.CONTRACT_ADDRESS_NOT_EXIST);
        }
        BlockHeader blockHeader = NulsContext.getInstance().getBestBlock().getHeader();
        // 当前区块状态根
        byte[] stateRoot = ContractUtil.getStateRoot(blockHeader);
        // 获取合约当前状态
        ProgramStatus status = vmHelper.getContractStatus(stateRoot, contractAddressBytes);
        boolean isTerminatedContract = ContractUtil.isTerminatedContract(status.ordinal());
        if (isTerminatedContract) {
            return Result.getFailed(ContractErrorCode.CONTRACT_DELETED);
        }
        byte[] senderBytes = AddressTool.getAddress(sender);
        if (!ArraysTool.arrayEquals(senderBytes, contractAddressInfoPo.getSender())) {
            return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_CREATER);
        }
        Result<ContractBalance> result = contractBalanceManager.getBalance(contractAddressBytes);
        ContractBalance balance = (ContractBalance) result.getData();
        if (balance == null) {
            return result;
        }
        Na totalBalance = balance.getBalance();
        if (totalBalance.compareTo(Na.ZERO) != 0) {
            return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_BALANCE);
        }
        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);
        }
        DeleteContractTransaction tx = new DeleteContractTransaction();
        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());
        // 组装txData
        DeleteContractData deleteContractData = new DeleteContractData();
        deleteContractData.setContractAddress(contractAddressBytes);
        deleteContractData.setSender(senderBytes);
        tx.setTxData(deleteContractData);
        // 计算CoinData
        /*
             * 没有Gas消耗,在终止智能合约里
             */
        CoinData coinData = new CoinData();
        // 总花费 终止智能合约的交易手续费按普通交易计算手续费
        CoinDataResult coinDataResult = accountLedgerService.getCoinData(senderBytes, Na.ZERO, 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);
        // 保存删除合约的交易到本地账本
        Result saveResult = accountLedgerService.verifyAndSaveUnconfirmedTransaction(tx);
        if (saveResult.isFailed()) {
            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);
            return sendResult;
        }
        return Result.getSuccess().setData(tx.getHash().getDigestHex());
    } catch (IOException e) {
        Log.error(e);
        Result result = Result.getFailed(ContractErrorCode.CONTRACT_TX_CREATE_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_TX_CREATE_ERROR);
        result.setMsg(e.getMessage());
        return result;
    }
}
Also used : Account(io.nuls.account.model.Account) ContractBalance(io.nuls.contract.ledger.module.ContractBalance) UnsupportedEncodingException(java.io.UnsupportedEncodingException) ECKey(io.nuls.core.tools.crypto.ECKey) IOException(java.io.IOException) DeleteContractTransaction(io.nuls.contract.entity.tx.DeleteContractTransaction) 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) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) NulsException(io.nuls.kernel.exception.NulsException) DeleteContractData(io.nuls.contract.entity.txdata.DeleteContractData) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

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