Search in sources :

Example 1 with ContractTransferTransaction

use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.

the class CallContractTxProcessor method onRollback.

@Override
public Result onRollback(CallContractTransaction tx, Object secondaryData) {
    try {
        // 回滚代币转账交易
        byte[] txHashBytes = null;
        try {
            txHashBytes = tx.getHash().serialize();
        } catch (IOException e) {
            Log.error(e);
        }
        ContractResult contractResult = tx.getContractResult();
        if (contractResult == null) {
            contractResult = contractService.getContractExecuteResult(tx.getHash());
        }
        CallContractData txData = tx.getTxData();
        byte[] senderContractAddressBytes = txData.getContractAddress();
        Result<ContractAddressInfoPo> senderContractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(senderContractAddressBytes);
        ContractAddressInfoPo po = senderContractAddressInfoResult.getData();
        if (po != null) {
            if (contractResult != null) {
                // 处理合约执行失败 - 没有transferEvent的情况, 直接从数据库中删除
                if (!contractResult.isSuccess()) {
                    if (ContractUtil.isTransferMethod(txData.getMethodName())) {
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(txData.getSender(), txHashBytes, new VarInt(0).encode()));
                    }
                }
                List<String> events = contractResult.getEvents();
                int size = events.size();
                // 目前只处理Transfer事件
                String event;
                ContractAddressInfoPo contractAddressInfo;
                if (events != null && size > 0) {
                    for (int i = 0; i < size; i++) {
                        event = events.get(i);
                        // 按照NRC20标准,TransferEvent事件中第一个参数是转出地址-from,第二个参数是转入地址-to, 第三个参数是金额
                        ContractTokenTransferInfoPo tokenTransferInfoPo = ContractUtil.convertJsonToTokenTransferInfoPo(event);
                        if (tokenTransferInfoPo == null) {
                            continue;
                        }
                        String contractAddress = tokenTransferInfoPo.getContractAddress();
                        if (StringUtils.isBlank(contractAddress)) {
                            continue;
                        }
                        if (!AddressTool.validAddress(contractAddress)) {
                            continue;
                        }
                        byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
                        if (ArraysTool.arrayEquals(senderContractAddressBytes, contractAddressBytes)) {
                            contractAddressInfo = po;
                        } else {
                            Result<ContractAddressInfoPo> contractAddressInfoResult = contractAddressStorageService.getContractAddressInfo(contractAddressBytes);
                            contractAddressInfo = contractAddressInfoResult.getData();
                        }
                        if (contractAddressInfo == null) {
                            continue;
                        }
                        // 事件不是NRC20合约的事件
                        if (!contractAddressInfo.isNrc20()) {
                            continue;
                        }
                        // 回滚token余额
                        this.rollbackContractToken(tokenTransferInfoPo);
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getFrom(), txHashBytes, new VarInt(i).encode()));
                        contractTokenTransferStorageService.deleteTokenTransferInfo(ArraysTool.concatenate(tokenTransferInfoPo.getTo(), txHashBytes, new VarInt(i).encode()));
                    }
                }
            }
        }
        // 删除子交易从全网账本
        // 删除子交易从合约账本
        // 删除子交易从本地账本
        List<ContractTransferTransaction> contractTransferTxList = this.extractContractTransferTxs(contractResult);
        if (contractTransferTxList != null && !contractTransferTxList.isEmpty()) {
            // 用于回滚本地账本
            List<Transaction> txList = new ArrayList<>();
            for (ContractTransferTransaction transferTx : contractTransferTxList) {
                try {
                    txList.add(transferTx);
                    Result result = ledgerService.rollbackTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("rollback contract transfer tx from ledger error. msg: {}", result.getMsg());
                        return result;
                    }
                    result = contractService.rollbackContractTransferTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("rollback contract transfer tx from contract ledger error. msg: {}", result.getMsg());
                        return Result.getFailed();
                    }
                } catch (Exception e) {
                    Log.error("rollback contract transfer tx error. msg: {}", e.getMessage());
                    return Result.getFailed();
                }
            }
            Result result = accountLedgerService.rollbackTransactions(txList);
            if (result.isFailed()) {
                Log.error("rollback contract transfer tx from account ledger error. msg: {}", result.getMsg());
                return Result.getFailed();
            }
        }
        // 删除合约调用交易的UTXO
        contractUtxoService.deleteUtxoOfTransaction(tx);
        // 删除合约执行结果
        contractService.deleteContractExecuteResult(tx.getHash());
    } catch (Exception e) {
        Log.error("rollback call contract tx error.", e);
        return Result.getFailed();
    }
    return Result.getSuccess();
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) VarInt(io.nuls.kernel.utils.VarInt) ArrayList(java.util.ArrayList) IOException(java.io.IOException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) IOException(java.io.IOException) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) Result(io.nuls.kernel.model.Result) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) Transaction(io.nuls.kernel.model.Transaction) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) ContractTokenTransferInfoPo(io.nuls.contract.dto.ContractTokenTransferInfoPo)

Example 2 with ContractTransferTransaction

use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.

the class ContractTransferTransactionStorageImpl method loadAllContractTransferTxList.

@Override
public List<ContractTransferTransaction> loadAllContractTransferTxList() throws NulsException {
    List<ContractTransferTransaction> txList = new ArrayList<>();
    List<Entry<byte[], byte[]>> entryList = dbService.entryList(ContractStorageConstant.DB_NAME_CONTRACT_SPECIAL_TX);
    if (entryList == null || entryList.isEmpty()) {
        return txList;
    }
    ContractTransferTransaction tx;
    for (Entry<byte[], byte[]> entry : entryList) {
        tx = new ContractTransferTransaction();
        tx.parse(entry.getValue(), 0);
        txList.add(tx);
    }
    return txList;
}
Also used : Entry(io.nuls.db.model.Entry) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) ArrayList(java.util.ArrayList)

Example 3 with ContractTransferTransaction

use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.

the class ContractTransferTransactionStorageImpl method getContractTransferTx.

@Override
public Result<ContractTransferTransaction> getContractTransferTx(NulsDigestData hash) {
    try {
        byte[] txBytes = dbService.get(ContractStorageConstant.DB_NAME_CONTRACT_SPECIAL_TX, hash.serialize());
        if (txBytes == null) {
            return Result.getSuccess();
        }
        ContractTransferTransaction contractTransferTransaction = new ContractTransferTransaction();
        contractTransferTransaction.parse(txBytes, 0);
        return Result.getSuccess().setData(contractTransferTransaction);
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed();
    }
}
Also used : ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) NulsException(io.nuls.kernel.exception.NulsException)

Example 4 with ContractTransferTransaction

use of io.nuls.contract.entity.tx.ContractTransferTransaction in project nuls by nuls-io.

the class CallContractTxProcessor method onCommit.

@Override
public Result onCommit(CallContractTransaction tx, Object secondaryData) {
    try {
        ContractResult contractResult = tx.getContractResult();
        // 保存调用合约交易的UTXO
        Result utxoResult = contractUtxoService.saveUtxoForContractAddress(tx);
        if (utxoResult.isFailed()) {
            Log.error("save confirmed contract utxo error, reason is {}.", utxoResult.getMsg());
            return utxoResult;
        }
        long blockHeight = tx.getBlockHeight();
        /**
         * 保存子交易到全网账本、合约账本、本地账本
         */
        Collection<ContractTransferTransaction> contractTransferTxs = tx.getContractTransferTxs();
        if (contractTransferTxs != null && contractTransferTxs.size() > 0) {
            for (ContractTransferTransaction transferTx : contractTransferTxs) {
                try {
                    transferTx.setBlockHeight(blockHeight);
                    Result result = ledgerService.saveTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("save contract transfer tx to ledger error. msg: {}", result.getMsg());
                        return result;
                    }
                    result = contractService.saveContractTransferTx(transferTx);
                    if (result.isFailed()) {
                        Log.error("save contract transfer tx to contract ledger error. msg: {}", result.getMsg());
                        return result;
                    }
                    result = accountLedgerService.saveConfirmedTransaction(transferTx);
                    if (result.isFailed()) {
                        Log.error("save contract transfer tx to account ledger error. msg: {}", result.getMsg());
                        return result;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.error("save contract transfer tx error. msg: {}", e.getMessage());
                    return Result.getFailed();
                }
            }
        }
        // 保存代币交易
        CallContractData callContractData = tx.getTxData();
        byte[] contractAddress = callContractData.getContractAddress();
        Result<ContractAddressInfoPo> contractAddressInfoPoResult = contractAddressStorageService.getContractAddressInfo(contractAddress);
        if (contractAddressInfoPoResult.isFailed()) {
            return contractAddressInfoPoResult;
        }
        ContractAddressInfoPo contractAddressInfoPo = contractAddressInfoPoResult.getData();
        if (contractAddressInfoPo == null) {
            return Result.getFailed(ContractErrorCode.CONTRACT_ADDRESS_NOT_EXIST);
        }
        contractResult.setNrc20(contractAddressInfoPo.isNrc20());
        BlockHeader blockHeader = tx.getBlockHeader();
        byte[] newestStateRoot = blockHeader.getStateRoot();
        // 获取合约当前状态
        ProgramStatus status = vmHelper.getContractStatus(newestStateRoot, contractAddress);
        boolean isTerminatedContract = ContractUtil.isTerminatedContract(status.ordinal());
        // 处理合约执行失败 - 没有transferEvent的情况, 直接从数据库中获取, 若是本地创建的交易,获取到修改为失败交易
        if (isTerminatedContract || !contractResult.isSuccess()) {
            if (contractAddressInfoPo != null && contractAddressInfoPo.isNrc20() && ContractUtil.isTransferMethod(callContractData.getMethodName())) {
                byte[] txHashBytes = tx.getHash().serialize();
                byte[] infoKey = ArraysTool.concatenate(callContractData.getSender(), txHashBytes, new VarInt(0).encode());
                Result<ContractTokenTransferInfoPo> infoResult = contractTokenTransferStorageService.getTokenTransferInfo(infoKey);
                ContractTokenTransferInfoPo po = infoResult.getData();
                if (po != null) {
                    po.setStatus((byte) 2);
                    contractTokenTransferStorageService.saveTokenTransferInfo(infoKey, po);
                    // 刷新token余额
                    if (isTerminatedContract) {
                        // 终止的合约,回滚token余额
                        this.rollbackContractToken(po);
                        contractResult.setError(true);
                        contractResult.setErrorMessage("this contract has been terminated");
                    } else {
                        if (po.getFrom() != null) {
                            vmHelper.refreshTokenBalance(newestStateRoot, contractAddressInfoPo, AddressTool.getStringAddressByBytes(po.getFrom()), po.getContractAddress());
                        }
                        if (po.getTo() != null) {
                            vmHelper.refreshTokenBalance(newestStateRoot, contractAddressInfoPo, AddressTool.getStringAddressByBytes(po.getTo()), po.getContractAddress());
                        }
                    }
                }
            }
        }
        if (!isTerminatedContract) {
            // 处理合约事件
            vmHelper.dealEvents(newestStateRoot, tx, contractResult, contractAddressInfoPo);
        }
        // 保存合约执行结果
        contractService.saveContractExecuteResult(tx.getHash(), contractResult);
    } catch (Exception e) {
        Log.error("save call contract tx error.", e);
        return Result.getFailed();
    }
    return Result.getSuccess();
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) VarInt(io.nuls.kernel.utils.VarInt) CallContractData(io.nuls.contract.entity.txdata.CallContractData) IOException(java.io.IOException) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) Result(io.nuls.kernel.model.Result) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) ContractTransferTransaction(io.nuls.contract.entity.tx.ContractTransferTransaction) ContractTokenTransferInfoPo(io.nuls.contract.dto.ContractTokenTransferInfoPo) BlockHeader(io.nuls.kernel.model.BlockHeader) ProgramStatus(io.nuls.contract.vm.program.ProgramStatus)

Aggregations

ContractTransferTransaction (io.nuls.contract.entity.tx.ContractTransferTransaction)4 ContractResult (io.nuls.contract.dto.ContractResult)2 ContractTokenTransferInfoPo (io.nuls.contract.dto.ContractTokenTransferInfoPo)2 CallContractData (io.nuls.contract.entity.txdata.CallContractData)2 ContractAddressInfoPo (io.nuls.contract.storage.po.ContractAddressInfoPo)2 Result (io.nuls.kernel.model.Result)2 VarInt (io.nuls.kernel.utils.VarInt)2 ValidateResult (io.nuls.kernel.validate.ValidateResult)2 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 CallContractTransaction (io.nuls.contract.entity.tx.CallContractTransaction)1 ProgramStatus (io.nuls.contract.vm.program.ProgramStatus)1 Entry (io.nuls.db.model.Entry)1 NulsException (io.nuls.kernel.exception.NulsException)1 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)1 BlockHeader (io.nuls.kernel.model.BlockHeader)1 Transaction (io.nuls.kernel.model.Transaction)1