Search in sources :

Example 6 with ContractTransfer

use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.

the class ContractServiceImpl method createReturnFundsContractTransfer.

private List<ContractTransfer> createReturnFundsContractTransfer(Transaction tx, Na sendBack) {
    // 合约执行失败而退回的转入金额暂时不收取手续费
    Na transferFee = Na.ZERO;
    if (sendBack.compareTo(transferFee) <= 0) {
        transferFee = sendBack;
    }
    List<ContractTransfer> contractTransferList = new ArrayList<>();
    try {
        Set<String> addressFromTX = SignatureUtil.getAddressFromTX(tx);
        if (addressFromTX == null || addressFromTX.size() == 0) {
            return contractTransferList;
        }
        Object[] array = addressFromTX.toArray();
        String fromAddress = (String) array[0];
        byte[] fromAddressBytes = AddressTool.getAddress(fromAddress);
        CoinData coinData = tx.getCoinData();
        List<Coin> toList = coinData.getTo();
        HashMap<String, Na> sendBackMap = MapUtil.createHashMap(toList.size());
        String ownerStr;
        for (Coin coin : toList) {
            if (!ArraysTool.arrayEquals(fromAddressBytes, coin.getOwner())) {
                ownerStr = AddressTool.getStringAddressByBytes(coin.getOwner());
                Na addressNa = sendBackMap.get(ownerStr);
                if (addressNa == null) {
                    sendBackMap.put(ownerStr, coin.getNa());
                } else {
                    sendBackMap.put(ownerStr, addressNa.add(coin.getNa()));
                }
            }
        }
        if (sendBackMap.size() > 0) {
            for (Map.Entry<String, Na> entry : sendBackMap.entrySet()) {
                ContractTransfer transfer = new ContractTransfer(AddressTool.getAddress(entry.getKey()), fromAddressBytes, entry.getValue(), transferFee, true);
                contractTransferList.add(transfer);
            }
        }
    } catch (NulsException e) {
        Log.error(e);
    }
    return contractTransferList;
}
Also used : ContractTransfer(io.nuls.contract.dto.ContractTransfer) LedgerUtil.asString(io.nuls.ledger.util.LedgerUtil.asString) NulsException(io.nuls.kernel.exception.NulsException)

Example 7 with ContractTransfer

use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.

the class ContractServiceImpl method generateContractTransfer.

private List<ContractTransfer> generateContractTransfer(List<ProgramTransfer> transfers) {
    if (transfers == null || transfers.size() == 0) {
        return new ArrayList<>(0);
    }
    List<ContractTransfer> resultList = new ArrayList<>(transfers.size());
    ContractTransfer contractTransfer;
    for (ProgramTransfer transfer : transfers) {
        contractTransfer = new ContractTransfer();
        contractTransfer.setFrom(transfer.getFrom());
        contractTransfer.setTo(transfer.getTo());
        contractTransfer.setValue(Na.valueOf(transfer.getValue().longValue()));
        contractTransfer.setFee(Na.ZERO);
        resultList.add(contractTransfer);
    }
    return resultList;
}
Also used : ContractTransfer(io.nuls.contract.dto.ContractTransfer)

Example 8 with ContractTransfer

use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.

the class ContractServiceImpl method filterContractNa.

private LinkedHashMap<String, Na>[] filterContractNa(List<ContractTransfer> transfers) {
    LinkedHashMap<String, Na> contractOutNa = MapUtil.createLinkedHashMap(4);
    LinkedHashMap<String, Na> contractInNa = MapUtil.createLinkedHashMap(4);
    LinkedHashMap<String, Na>[] contracts = new LinkedHashMap[2];
    contracts[0] = contractOutNa;
    contracts[1] = contractInNa;
    byte[] from, to;
    Na transferValue;
    for (ContractTransfer transfer : transfers) {
        from = transfer.getFrom();
        to = transfer.getTo();
        transferValue = transfer.getValue();
        if (ContractUtil.isLegalContractAddress(from)) {
            String contract = asString(from);
            Na na = contractOutNa.get(contract);
            if (na == null) {
                contractOutNa.put(contract, transferValue);
            } else {
                contractOutNa.put(contract, na.add(transferValue));
            }
        }
        if (ContractUtil.isLegalContractAddress(to)) {
            String contract = asString(to);
            Na na = contractInNa.get(contract);
            if (na == null) {
                contractInNa.put(contract, transferValue);
            } else {
                contractInNa.put(contract, na.add(transferValue));
            }
        }
    }
    return contracts;
}
Also used : ContractTransfer(io.nuls.contract.dto.ContractTransfer) LedgerUtil.asString(io.nuls.ledger.util.LedgerUtil.asString)

Example 9 with ContractTransfer

use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.

the class ContractServiceImpl method handleContractTransferTxs.

private byte[] handleContractTransferTxs(CallContractTransaction tx, ContractResult contractResult, byte[] stateRoot, byte[] preStateRoot, List<ContractTransfer> transfers, long time, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long blockHeight) {
    boolean isCorrectContractTransfer = true;
    // 用于保存本次交易产生的合约转账(从合约转出)交易
    Map<String, ContractTransferTransaction> successContractTransferTxs = new LinkedHashMap<>();
    // 创建合约转账(从合约转出)交易
    if (transfers != null && transfers.size() > 0) {
        Result<ContractTransferTransaction> contractTransferResult;
        do {
            // 验证合约转账(从合约转出)交易的最小转移金额
            Result result = this.verifyTransfer(transfers);
            if (result.isFailed()) {
                isCorrectContractTransfer = false;
                contractResult.setError(true);
                String errorMsg = contractResult.getErrorMessage();
                errorMsg = errorMsg == null ? result.getErrorCode().getEnMsg() : (errorMsg + "," + result.getErrorCode().getEnMsg());
                contractResult.setErrorMessage(errorMsg);
                break;
            }
            // 合约转账(从合约转出)使用的交易时间为区块时间
            ContractTransferTransaction contractTransferTx;
            for (ContractTransfer transfer : transfers) {
                // 保存外部合约交易hash
                transfer.setOrginHash(tx.getHash());
                contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
                if (contractTransferResult.isFailed()) {
                    this.rollbackContractTransferTxs(successContractTransferTxs, toMaps, contractUsedCoinMap);
                    isCorrectContractTransfer = false;
                    contractResult.setError(true);
                    String errorMsg = contractResult.getErrorMessage();
                    errorMsg = errorMsg == null ? contractTransferResult.getMsg() : (errorMsg + "," + contractTransferResult.getMsg());
                    contractResult.setErrorMessage(errorMsg);
                    break;
                }
                contractTransferTx = contractTransferResult.getData();
                // 保存内部转账交易hash
                transfer.setHash(contractTransferTx.getHash());
                successContractTransferTxs.put(contractTransferTx.getHash().getDigestHex(), contractTransferTx);
            }
        } while (false);
        // 如果合约转账(从合约转出)出现错误,整笔合约交易视作合约执行失败
        if (!isCorrectContractTransfer) {
            if (Log.isDebugEnabled()) {
                Log.debug("contract transfer execution failed, reason: {}", contractResult.getErrorMessage());
            }
            // 执行合约产生的状态根回滚到上一个世界状态
            stateRoot = preStateRoot;
            contractResult.setStateRoot(stateRoot);
            // 余额还原到上一次的余额
            contractResult.setBalance(contractResult.getPreBalance());
            // 清空成功转账列表
            successContractTransferTxs.clear();
            // 回滚临时余额
            this.rollbackContractTempBalance(tx, contractResult);
            // 清空内部转账列表
            transfers.clear();
            // 合约转账(从合约转出)交易失败,且调用者存在资金转入合约地址,创建一笔合约转账(从合约转出),退回这笔资金
            if (contractResult.getValue() > 0) {
                Na sendBack = Na.valueOf(contractResult.getValue());
                List<ContractTransfer> transferList = this.createReturnFundsContractTransfer(tx, sendBack);
                for (ContractTransfer transfer : transferList) {
                    transfer.setOrginHash(tx.getHash());
                    contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
                    if (contractTransferResult.isFailed()) {
                        successContractTransferTxs.clear();
                        contractResult.setErrorMessage(contractResult.getErrorMessage() + ", " + contractTransferResult.getMsg());
                        break;
                    } else {
                        ContractTransferTransaction _contractTransferTx = contractTransferResult.getData();
                        // 保存内部转账交易hash和外部合约交易hash
                        transfer.setHash(_contractTransferTx.getHash());
                        transfers.add(transfer);
                        successContractTransferTxs.put(_contractTransferTx.getHash().getDigestHex(), _contractTransferTx);
                    }
                }
            }
        } else {
            // 归集转入合约地址的UTXOs
            this.contractExchange(tx, contractResult, time, toMaps, contractUsedCoinMap, blockHeight, transfers, successContractTransferTxs);
        }
        // 保存内部转账子交易到父交易对象中
        tx.setContractTransferTxs(successContractTransferTxs.values());
    } else {
        // `transfers.size() == 0` 智能合约在打包节点上只执行一次(打包区块和验证区块), 打包节点在打包时已处理过, 不重复处理
        if (null != transfers && transfers.size() == 0) {
            this.contractExchange(tx, contractResult, time, toMaps, contractUsedCoinMap, blockHeight, transfers, successContractTransferTxs);
            tx.setContractTransferTxs(successContractTransferTxs.values());
        }
    }
    // 合约执行成功并且合约转账(从合约转出)执行成功,提交这笔交易
    if (contractResult.isSuccess() && isCorrectContractTransfer) {
        Object txTrackObj = contractResult.getTxTrack();
        if (txTrackObj != null && txTrackObj instanceof ProgramExecutor) {
            ProgramExecutor txTrack = (ProgramExecutor) txTrackObj;
            if (Log.isDebugEnabled()) {
                Log.debug("===tx track commit.");
            }
            txTrack.commit();
        }
    }
    return stateRoot;
}
Also used : ContractTransfer(io.nuls.contract.dto.ContractTransfer) LedgerUtil.asString(io.nuls.ledger.util.LedgerUtil.asString) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 10 with ContractTransfer

use of io.nuls.contract.dto.ContractTransfer in project nuls by nuls-io.

the class ContractServiceImpl method doContractExchange.

private void doContractExchange(NulsDigestData hash, byte[] contractAddress, long transferValue, long time, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long blockHeight, List<ContractTransfer> transfers, Map<String, ContractTransferTransaction> successContractTransferTxs) {
    BigInteger currentBalance = vmContext.getBalance(contractAddress, blockHeight);
    long currentBalanceLongValue = currentBalance.longValue();
    if (currentBalanceLongValue == 0 || currentBalanceLongValue == transferValue) {
        // 余额等于0不归集
        return;
    }
    ContractTransfer transfer = new ContractTransfer(contractAddress, contractAddress, Na.valueOf(currentBalanceLongValue), Na.ZERO, false);
    transfer.setOrginHash(hash);
    Result<ContractTransferTransaction> contractTransferResult = this.createContractTransferTx(transfer, time, toMaps, contractUsedCoinMap, blockHeight);
    if (contractTransferResult.isSuccess()) {
        ContractTransferTransaction _contractTransferTx = contractTransferResult.getData();
        if (!this.needExchange(_contractTransferTx)) {
            return;
        }
        Log.info("Contract UTXOs need exchange, orgin tx hash is {}, current tx hash is {}", hash.toString(), _contractTransferTx.getHash().toString());
        // 保存内部转账交易hash和外部合约交易hash
        transfer.setHash(_contractTransferTx.getHash());
        transfers.add(transfer);
        successContractTransferTxs.put(_contractTransferTx.getHash().getDigestHex(), _contractTransferTx);
    }
}
Also used : ContractTransfer(io.nuls.contract.dto.ContractTransfer) BigInteger(java.math.BigInteger)

Aggregations

ContractTransfer (io.nuls.contract.dto.ContractTransfer)10 LedgerUtil.asString (io.nuls.ledger.util.LedgerUtil.asString)4 ContractResult (io.nuls.contract.dto.ContractResult)2 BigInteger (java.math.BigInteger)2 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)1 CallContractTransaction (io.nuls.contract.entity.tx.CallContractTransaction)1 ContractTransferTransaction (io.nuls.contract.entity.tx.ContractTransferTransaction)1 NulsException (io.nuls.kernel.exception.NulsException)1 ByteArrayWrapper (io.nuls.kernel.utils.ByteArrayWrapper)1 ValidateResult (io.nuls.kernel.validate.ValidateResult)1 UtxoAccountsBalancePo (io.nuls.utxo.accounts.storage.po.UtxoAccountsBalancePo)1 LinkedList (java.util.LinkedList)1