Search in sources :

Example 6 with ContractResult

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

the class ContractServiceImpl method invokeContract.

private Result<ContractResult> invokeContract(ProgramExecutor track, Transaction tx, long height, byte[] stateRoot, boolean isForkChain) {
    if (tx == null || height < 0) {
        return Result.getFailed(KernelErrorCode.PARAMETER_ERROR);
    }
    int txType = tx.getType();
    // 分叉链切换主链时,重新执行智能合约
    if (!isForkChain) {
        ContractTransaction contractTx = (ContractTransaction) tx;
        // 打包、验证区块,合约只执行一次
        ContractResult contractExecutedResult;
        contractExecutedResult = contractTx.getContractResult();
        if (contractExecutedResult == null) {
            contractExecutedResult = getContractExecuteResult(tx.getHash());
            if (contractExecutedResult != null) {
                if (Log.isDebugEnabled()) {
                    Log.debug("===get ContractResult from db.");
                }
            }
        } else {
            if (Log.isDebugEnabled()) {
                Log.debug("===get ContractResult from tx object.");
            }
        }
        if (contractExecutedResult != null) {
            contractExecutedResult.setTxTrack(track);
            if (contractExecutedResult.isSuccess()) {
                // 刷新临时余额
                if (contractExecutedResult.isSuccess()) {
                    if (tx instanceof CallContractTransaction) {
                        this.refreshTempBalance((CallContractTransaction) tx, contractExecutedResult, height);
                    }
                } else {
                    // 合约调用失败,把需要退还的UTXO记录到结果对象中
                    contractExecutedResult.setValue(((ContractData) tx.getTxData()).getValue());
                }
                return Result.getSuccess().setData(contractExecutedResult);
            } else {
                if (Log.isDebugEnabled()) {
                    Log.debug("contractExecutedResult failed. {}", contractExecutedResult.toString());
                }
                return Result.getFailed().setData(contractExecutedResult);
            }
        }
    }
    if (txType == TX_TYPE_CREATE_CONTRACT) {
        CreateContractTransaction createContractTransaction = (CreateContractTransaction) tx;
        CreateContractData createContractData = createContractTransaction.getTxData();
        if (!ContractUtil.checkPrice(createContractData.getPrice())) {
            return Result.getFailed(ContractErrorCode.CONTRACT_MINIMUM_PRICE);
        }
        Result<ContractResult> result = createContract(track, height, stateRoot, createContractData);
        ContractResult contractResult = result.getData();
        if (contractResult != null && contractResult.isSuccess()) {
            Result nrc20Result = vmHelper.validateNrc20Contract((ProgramExecutor) contractResult.getTxTrack(), createContractTransaction, contractResult);
            if (nrc20Result.isFailed()) {
                contractResult.setError(true);
                if (ContractErrorCode.CONTRACT_NRC20_SYMBOL_FORMAT_INCORRECT.equals(nrc20Result.getErrorCode())) {
                    contractResult.setErrorMessage("The format of the symbol is incorrect.");
                } else if (ContractErrorCode.CONTRACT_NAME_FORMAT_INCORRECT.equals(nrc20Result.getErrorCode())) {
                    contractResult.setErrorMessage("The format of the name is incorrect.");
                } else if (ContractErrorCode.CONTRACT_NRC20_MAXIMUM_DECIMALS.equals(nrc20Result.getErrorCode())) {
                    contractResult.setErrorMessage("The value of decimals ranges from 0 to 18.");
                } else if (ContractErrorCode.CONTRACT_NRC20_MAXIMUM_TOTAL_SUPPLY.equals(nrc20Result.getErrorCode())) {
                    contractResult.setErrorMessage("The value of totalSupply ranges from 1 to 2^256 - 1.");
                } else {
                    contractResult.setErrorMessage("Unkown error.");
                }
                result.setData(contractResult);
            }
        }
        return result;
    } else if (txType == TX_TYPE_CALL_CONTRACT) {
        CallContractTransaction callContractTransaction = (CallContractTransaction) tx;
        CallContractData callContractData = callContractTransaction.getTxData();
        if (!ContractUtil.checkPrice(callContractData.getPrice())) {
            return Result.getFailed(ContractErrorCode.CONTRACT_MINIMUM_PRICE);
        }
        Result<ContractResult> result = callContract(track, height, stateRoot, callContractData);
        byte[] contractAddress = callContractData.getContractAddress();
        BigInteger preBalance = vmContext.getBalance(contractAddress, height);
        ContractResult contractResult = result.getData();
        if (!contractResult.isSuccess()) {
            if (Log.isDebugEnabled()) {
                Log.debug("contractResult failed. {}", contractResult.toString());
            }
        }
        contractResult.setPreBalance(preBalance);
        // 刷新临时余额
        if (result.isSuccess()) {
            this.refreshTempBalance(callContractTransaction, contractResult, height);
        } else {
            // 合约调用失败,把需要退还的UTXO记录到结果对象中
            contractResult.setValue(callContractData.getValue());
        }
        return result;
    } else if (txType == TX_TYPE_DELETE_CONTRACT) {
        DeleteContractTransaction deleteContractTransaction = (DeleteContractTransaction) tx;
        DeleteContractData deleteContractData = deleteContractTransaction.getTxData();
        Result<ContractResult> result = deleteContract(track, height, stateRoot, deleteContractData);
        return result;
    } else {
        return Result.getSuccess();
    }
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) BigInteger(java.math.BigInteger) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 7 with ContractResult

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

the class ForkChainProcess method doChange.

private boolean doChange(List<Block> successList, ChainContainer originalForkChain, List<Object[]> verifyResultList) {
    boolean changeSuccess = true;
    // add new block
    List<Block> addBlockList = originalForkChain.getChain().getAllBlockList();
    Result<Block> preBlockResult = blockService.getBlock(addBlockList.get(0).getHeader().getPreHash());
    Block preBlock = preBlockResult.getData();
    Block newBlock;
    // for (Block newBlock : addBlockList) {
    for (int i = 0, size = addBlockList.size(); i < size; i++) {
        newBlock = addBlockList.get(i);
        newBlock.verifyWithException();
        Map<String, Coin> toMaps = new HashMap<>();
        Set<String> fromSet = new HashSet<>();
        /**
         * pierre add 智能合约相关
         */
        long bestHeight = preBlock.getHeader().getHeight();
        byte[] stateRoot = ConsensusTool.getStateRoot(preBlock.getHeader());
        preBlock = newBlock;
        BlockHeader verifyHeader = newBlock.getHeader();
        byte[] receiveStateRoot = ConsensusTool.getStateRoot(verifyHeader);
        ContractResult contractResult;
        Map<String, Coin> contractUsedCoinMap = new HashMap<>();
        int totalGasUsed = 0;
        // 为本次验证区块增加一个合约的临时余额区,用于记录本次合约地址余额的变化
        contractService.createContractTempBalance();
        // 为本次验证区块创建一个批量执行合约的执行器
        contractService.createBatchExecute(stateRoot);
        // 为本次验证区块存储当前块的部分区块头信息(高度、时间、打包者地址)
        BlockHeader tempHeader = new BlockHeader();
        tempHeader.setTime(verifyHeader.getTime());
        tempHeader.setHeight(verifyHeader.getHeight());
        tempHeader.setPackingAddress(verifyHeader.getPackingAddress());
        contractService.createCurrentBlockHeader(tempHeader);
        List<ContractResult> contractResultList = new ArrayList<>();
        // 用于存储合约执行结果的stateRoot, 如果不为空,则说明验证、打包的区块是同一个节点
        byte[] tempStateRoot = null;
        for (Transaction tx : newBlock.getTxs()) {
            if (tx.isSystemTx()) {
                continue;
            }
            // 区块中可以消耗的最大Gas总量,超过这个值,如果还有消耗GAS的合约交易,则本区块中不再继续验证区块
            if (totalGasUsed > ContractConstant.MAX_PACKAGE_GAS) {
                if (ContractUtil.isGasCostContractTransaction(tx)) {
                    Log.info("verify block failed: Excess contract transaction detected.");
                    changeSuccess = false;
                    break;
                }
            }
            ValidateResult result = tx.verify();
            if (result.isSuccess()) {
                result = ledgerService.verifyCoinData(tx, toMaps, fromSet, bestHeight);
                if (result.isFailed()) {
                    ErrorData errorData = (ErrorData) result.getData();
                    if (null == errorData) {
                        Log.info("failed message:" + result.getMsg());
                    } else {
                        Log.info("failed message:" + errorData.getMsg());
                    }
                    changeSuccess = false;
                    break;
                }
            } else {
                ErrorData errorData = (ErrorData) result.getData();
                if (null == errorData) {
                    Log.info("failed message:" + result.getMsg());
                } else {
                    Log.info("failed message:" + errorData.getMsg());
                }
                changeSuccess = false;
                break;
            }
            // 验证时发现智能合约交易就调用智能合约
            if (ContractUtil.isContractTransaction(tx)) {
                contractResult = contractService.batchProcessTx(tx, bestHeight, newBlock, stateRoot, toMaps, contractUsedCoinMap, true).getData();
                if (contractResult != null) {
                    tempStateRoot = contractResult.getStateRoot();
                    totalGasUsed += contractResult.getGasUsed();
                    contractResultList.add(contractResult);
                }
            }
        }
        if (!changeSuccess) {
            break;
        }
        // 验证结束后移除临时余额区
        contractService.removeContractTempBalance();
        stateRoot = contractService.commitBatchExecute().getData();
        // 验证结束后移除批量执行合约的执行器
        contractService.removeBatchExecute();
        // 验证结束后移除当前区块头信息
        contractService.removeCurrentBlockHeader();
        // 如果不为空,则说明验证、打包的区块是同一个节点
        if (tempStateRoot != null) {
            stateRoot = tempStateRoot;
        }
        newBlock.getHeader().setStateRoot(stateRoot);
        for (ContractResult result : contractResultList) {
            result.setStateRoot(stateRoot);
        }
        // 验证世界状态根
        if ((receiveStateRoot != null || stateRoot != null) && !Arrays.equals(receiveStateRoot, stateRoot)) {
            Log.info("contract stateRoot incorrect. receiveStateRoot is {}, stateRoot is {}.", receiveStateRoot != null ? Hex.encode(receiveStateRoot) : receiveStateRoot, stateRoot != null ? Hex.encode(stateRoot) : stateRoot);
            changeSuccess = false;
            break;
        }
        // 验证CoinBase交易
        Object[] objects = verifyResultList.get(i);
        MeetingRound currentRound = (MeetingRound) objects[0];
        MeetingMember member = (MeetingMember) objects[1];
        if (!chainManager.getMasterChain().verifyCoinBaseTx(newBlock, currentRound, member)) {
            changeSuccess = false;
            break;
        }
        if (!changeSuccess) {
            break;
        }
        ValidateResult validateResult1 = tansactionService.conflictDetect(newBlock.getTxs());
        if (validateResult1.isFailed()) {
            Log.info("failed message:" + validateResult1.getMsg());
            changeSuccess = false;
            break;
        }
        try {
            Result result = blockService.saveBlock(newBlock);
            boolean success = result.isSuccess();
            if (success) {
                // 更新版本协议内容
                successList.add(newBlock);
                nulsProtocolProcess.processProtocolUpGrade(newBlock.getHeader());
                BlockHeader preHeader = blockService.getBlockHeader(newBlock.getHeader().getPreHash()).getData();
                randomSeedService.processBlock(newBlock.getHeader(), preHeader);
            } else {
                ChainLog.debug("save block error : " + result.getMsg() + " , block height : " + newBlock.getHeader().getHeight() + " , hash: " + newBlock.getHeader().getHash());
                changeSuccess = false;
                break;
            }
        } catch (Exception e) {
            Log.info("change fork chain error at save block, ", e);
            changeSuccess = false;
            break;
        }
    }
    if (!changeSuccess) {
        contractService.removeContractTempBalance();
        contractService.removeBatchExecute();
        contractService.removeCurrentBlockHeader();
    }
    return changeSuccess;
}
Also used : MeetingMember(io.nuls.consensus.poc.model.MeetingMember) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) MeetingRound(io.nuls.consensus.poc.model.MeetingRound) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException)

Example 8 with ContractResult

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

the class BlockProcess method addBlock.

/**
 * Dealing with new blocks, the new block has two cases, the block when downloading and the latest block received, there are two different authentication logic
 *      * The download block is added. The verification round is not the current round. You need to restore the block to generate the current round status.
 *      * The new block received during operation must be verified with the latest round status
 *      * New block processing flow:
 *      * 1. Preprocessing, basic verification, including verification of block header field information, block size verification, signature verification
 *      * 2, try to add blocks to the main chain, first verify the block of the round and packaged people, if the verification fails, then put into the isolated block pool, if the verification is successful, then add into the main chain, add the memory state into
 *      * 3, verify the transaction of the block is legitimate, whether there are double flowers or other illegal transactions, if there is, then put in the isolated block pool, if not, save the block
 *      * 4, save the block header information, save the block transaction information
 *      * 5. Forwarding block
 * <p>
 * 处理新的区块,新区块有两种情况,下载时的区块和接收到的最新区块,两种有不同的验证逻辑
 * 下载中区块的添加,验证的轮次不是当前的轮次,需要还原区块产生当时的轮次状态
 * 运行中接收到的新区块,必须以当前最新的轮次状态来验证
 * 新区块处理的流程:
 * 1、预处理,做基本的验证,包括区块头字段信息的验证,区块大小的验证,签名的验证
 * 2、尝试向主链添加区块,先验证区块的轮次和打包人,如果验证失败则放入孤立区块池,如果验证成功,则添加进主链里,内存状态添加进去
 * 3、验证区块的交易是否合法,是否有双花或者其它不合法的交易,如果有,则放入孤立区块池里,如果没有,则保存区块
 * 4、保存区块头信息,保存区块交易信息
 * 5、转发区块
 *
 * @return boolean
 */
public boolean addBlock(BlockContainer blockContainer) throws IOException {
    if (NulsContext.mastUpGrade == true) {
        return false;
    }
    boolean isDownload = blockContainer.getStatus() == BlockContainerStatus.DOWNLOADING;
    Block block = blockContainer.getBlock();
    // 丢弃掉未来时间的区块
    if (TimeService.currentTimeMillis() + PocConsensusConstant.DISCARD_FUTURE_BLOCKS_TIME < block.getHeader().getTime()) {
        return false;
    }
    // Verify the the block, the content to be verified includes: whether the block size exceeds the limit,
    // whether the attribute of the block header is legal, the Merkel tree root is correct, the signature is correct,
    // and whether the expanded round of information is valid
    // 验证区块,需要验证的内容有:区块大小是否超过限制、区块头属性是否合法、梅克尔树根是否正确、签名是否正确、扩展的轮次信息是否合法
    block.verifyWithException();
    bifurcationUtil.validate(block.getHeader());
    ValidateResult<List<Transaction>> validateResult = ledgerService.verifyDoubleSpend(block);
    if (validateResult.isFailed() && validateResult.getErrorCode().equals(TransactionErrorCode.TRANSACTION_REPEATED)) {
        RedPunishTransaction redPunishTransaction = new RedPunishTransaction();
        RedPunishData redPunishData = new RedPunishData();
        byte[] packingAddress = AddressTool.getAddress(block.getHeader().getBlockSignature().getPublicKey());
        List<Agent> agentList = PocConsensusContext.getChainManager().getMasterChain().getChain().getAgentList();
        Agent agent = null;
        for (Agent a : agentList) {
            if (a.getDelHeight() > 0) {
                continue;
            }
            if (Arrays.equals(a.getPackingAddress(), packingAddress)) {
                agent = a;
                break;
            }
        }
        if (null == agent) {
            return false;
        }
        redPunishData.setAddress(agent.getAgentAddress());
        SmallBlock smallBlock = new SmallBlock();
        smallBlock.setHeader(block.getHeader());
        smallBlock.setTxHashList(block.getTxHashList());
        for (Transaction tx : validateResult.getData()) {
            smallBlock.addBaseTx(tx);
        }
        redPunishData.setEvidence(smallBlock.serialize());
        redPunishData.setReasonCode(PunishReasonEnum.DOUBLE_SPEND.getCode());
        redPunishTransaction.setTxData(redPunishData);
        redPunishTransaction.setTime(smallBlock.getHeader().getTime());
        CoinData coinData = ConsensusTool.getStopAgentCoinData(agent, redPunishTransaction.getTime() + PocConsensusConstant.RED_PUNISH_LOCK_TIME);
        redPunishTransaction.setCoinData(coinData);
        redPunishTransaction.setHash(NulsDigestData.calcDigestData(redPunishTransaction.serializeForHash()));
        TxMemoryPool.getInstance().add(redPunishTransaction, false);
        return false;
    }
    // Verify that the block round information is correct, if correct, join the main chain
    // 验证区块轮次信息是否正确、如果正确,则加入主链
    Result verifyAndAddBlockResult = chainManager.getMasterChain().verifyAndAddBlock(block, isDownload, false);
    if (verifyAndAddBlockResult.isSuccess()) {
        boolean success = true;
        try {
            do {
                // Verify that the block transaction is valid, save the block if the verification passes, and discard the block if it fails
                // 验证区块交易是否合法,如果验证通过则保存区块,如果失败则丢弃该块
                long time = System.currentTimeMillis();
                List<Future<Boolean>> futures = new ArrayList<>();
                List<Transaction> txs = block.getTxs();
                // 首先验证区块里的所有交易是否都属于当前版本的交易,如果有不包含的交易类型,丢弃该区块
                Set<Integer> txTypeSet = NulsVersionManager.getMainProtocolContainer().getTxMap().keySet();
                for (Transaction tx : txs) {
                    if (!txTypeSet.contains(tx.getType())) {
                        Log.info("--------------------- block tx discard, current protocol version:" + NulsVersionManager.getMainProtocolContainer().getVersion() + ",  tx.type:" + tx.getType());
                        return false;
                    }
                }
                for (Transaction tx : txs) {
                    Future<Boolean> res = signExecutor.submit(new Callable<Boolean>() {

                        @Override
                        public Boolean call() throws Exception {
                            ValidateResult verify = tx.verify();
                            /**
                             ***********************************************************
                             */
                            if (verify.isFailed()) {
                                Log.error(JSONUtils.obj2json(verify.getErrorCode()));
                            }
                            /**
                             ***********************************************************
                             */
                            boolean result = verify.isSuccess();
                            return result;
                        }
                    });
                    futures.add(res);
                }
                Map<String, Coin> toMaps = new HashMap<>();
                Set<String> fromSet = new HashSet<>();
                /**
                 * pierre add 智能合约相关
                 */
                BlockHeader bestBlockHeader = NulsContext.getInstance().getBestBlock().getHeader();
                BlockHeader verifyHeader = block.getHeader();
                long bestHeight = bestBlockHeader.getHeight();
                byte[] receiveStateRoot = ConsensusTool.getStateRoot(verifyHeader);
                byte[] stateRoot = ConsensusTool.getStateRoot(bestBlockHeader);
                ContractResult contractResult;
                Map<String, Coin> contractUsedCoinMap = new HashMap<>();
                int totalGasUsed = 0;
                // 为本次验证区块增加一个合约的临时余额区,用于记录本次合约地址余额的变化
                contractService.createContractTempBalance();
                // 为本次验证区块创建一个批量执行合约的执行器
                contractService.createBatchExecute(stateRoot);
                // 为本次验证区块存储当前块的部分区块头信息(高度、时间、打包者地址)
                BlockHeader tempHeader = new BlockHeader();
                tempHeader.setTime(verifyHeader.getTime());
                tempHeader.setHeight(verifyHeader.getHeight());
                tempHeader.setPackingAddress(verifyHeader.getPackingAddress());
                contractService.createCurrentBlockHeader(tempHeader);
                List<ContractResult> contractResultList = new ArrayList<>();
                // 用于存储合约执行结果的stateRoot, 如果不为空,则说明验证、打包的区块是同一个节点
                byte[] tempStateRoot = null;
                for (Transaction tx : txs) {
                    if (tx.isSystemTx()) {
                        continue;
                    }
                    // 区块中可以消耗的最大Gas总量,超过这个值,如果还有消耗GAS的合约交易,则本区块中不再继续验证区块
                    if (totalGasUsed > ContractConstant.MAX_PACKAGE_GAS) {
                        if (ContractUtil.isGasCostContractTransaction(tx)) {
                            Log.info("verify block failed: Excess contract transaction detected.");
                            success = false;
                            break;
                        }
                    }
                    ValidateResult result = ledgerService.verifyCoinData(tx, toMaps, fromSet);
                    if (result.isFailed()) {
                        Log.info("failed message:" + result.getMsg());
                        success = false;
                        break;
                    }
                    // 验证时发现智能合约交易就调用智能合约
                    if (ContractUtil.isContractTransaction(tx)) {
                        contractResult = contractService.batchProcessTx(tx, bestHeight, block, stateRoot, toMaps, contractUsedCoinMap, false).getData();
                        if (contractResult != null) {
                            tempStateRoot = contractResult.getStateRoot();
                            totalGasUsed += contractResult.getGasUsed();
                            contractResultList.add(contractResult);
                        }
                    }
                }
                if (!success) {
                    break;
                }
                // 验证结束后移除临时余额区
                contractService.removeContractTempBalance();
                stateRoot = contractService.commitBatchExecute().getData();
                // 验证结束后移除批量执行合约的执行器
                contractService.removeBatchExecute();
                // 验证结束后移除当前区块头信息
                contractService.removeCurrentBlockHeader();
                // 如果不为空,则说明验证、打包的区块是同一个节点
                if (tempStateRoot != null) {
                    stateRoot = tempStateRoot;
                }
                block.getHeader().setStateRoot(stateRoot);
                for (ContractResult result : contractResultList) {
                    result.setStateRoot(stateRoot);
                }
                // 验证世界状态根
                if ((receiveStateRoot != null || stateRoot != null) && !Arrays.equals(receiveStateRoot, stateRoot)) {
                    Log.info("contract stateRoot incorrect. receiveStateRoot is {}, stateRoot is {}.", receiveStateRoot != null ? Hex.encode(receiveStateRoot) : receiveStateRoot, stateRoot != null ? Hex.encode(stateRoot) : stateRoot);
                    success = false;
                    break;
                }
                // 验证CoinBase交易
                Object[] objects = (Object[]) verifyAndAddBlockResult.getData();
                MeetingRound currentRound = (MeetingRound) objects[0];
                MeetingMember member = (MeetingMember) objects[1];
                if (!chainManager.getMasterChain().verifyCoinBaseTx(block, currentRound, member)) {
                    success = false;
                    break;
                }
                if (!success) {
                    break;
                }
                ValidateResult validateResult1 = tansactionService.conflictDetect(block.getTxs());
                if (validateResult1.isFailed()) {
                    success = false;
                    Log.info("failed message:" + validateResult1.getMsg());
                    break;
                }
                for (Future<Boolean> future : futures) {
                    if (!future.get()) {
                        success = false;
                        Log.info("verify failed!");
                        break;
                    }
                }
                // Log.info("验证交易耗时:" + (System.currentTimeMillis() - time));
                if (!success) {
                    break;
                }
                time = System.currentTimeMillis();
                // save block
                Result result = blockService.saveBlock(block);
                success = result.isSuccess();
                if (!success) {
                    Log.warn("save block fail : reason : " + result.getMsg() + ", block height : " + block.getHeader().getHeight() + ", hash : " + block.getHeader().getHash());
                } else {
                    randomSeedService.processBlock(block.getHeader(), bestBlockHeader);
                    RewardStatisticsProcess.addBlock(block);
                    // 更新版本协议内容
                    nulsProtocolProcess.processProtocolUpGrade(block.getHeader());
                    BlockLog.debug("save block height : " + block.getHeader().getHeight() + " , hash : " + block.getHeader().getHash());
                }
            // Log.info("保存耗时:" + (System.currentTimeMillis() - time));
            } while (false);
        } catch (Exception e) {
            Log.error("save block error : " + e.getMessage(), e);
        }
        if (success) {
            long t = System.currentTimeMillis();
            NulsContext.getInstance().setBestBlock(block);
            // remove tx from memory pool
            removeTxFromMemoryPool(block);
            // Log.info("移除内存交易耗时:" + (System.currentTimeMillis() - t));
            // 转发区块
            forwardingBlock(blockContainer);
            return true;
        } else {
            contractService.removeContractTempBalance();
            contractService.removeBatchExecute();
            contractService.removeCurrentBlockHeader();
            chainManager.getMasterChain().rollback(block);
            NulsContext.getInstance().setBestBlock(chainManager.getBestBlock());
            Log.error("save block fail : " + block.getHeader().getHeight() + " , isDownload : " + isDownload);
        }
    } else {
        // 下载中验证失败的区块直接丢弃
        if (isDownload && !ConsensusStatusContext.isRunning()) {
            return false;
        }
        boolean hasFoundForkChain = checkAndAddForkChain(block);
        if (!hasFoundForkChain) {
            ChainLog.debug("add block {} - {} in queue", block.getHeader().getHeight(), block.getHeader().getHash().getDigestHex());
            orphanBlockProvider.addBlock(blockContainer);
        }
    }
    return false;
}
Also used : RedPunishTransaction(io.nuls.consensus.poc.protocol.tx.RedPunishTransaction) MeetingMember(io.nuls.consensus.poc.model.MeetingMember) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) RedPunishData(io.nuls.consensus.poc.protocol.entity.RedPunishData) MeetingRound(io.nuls.consensus.poc.model.MeetingRound) SmallBlock(io.nuls.protocol.model.SmallBlock) Agent(io.nuls.consensus.poc.protocol.entity.Agent) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) IOException(java.io.IOException) RedPunishTransaction(io.nuls.consensus.poc.protocol.tx.RedPunishTransaction) SmallBlock(io.nuls.protocol.model.SmallBlock) Future(java.util.concurrent.Future)

Example 9 with ContractResult

use of io.nuls.contract.dto.ContractResult 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)

Example 10 with ContractResult

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

the class CreateContractTxProcessor method onCommit.

@Override
public Result onCommit(CreateContractTransaction tx, Object secondaryData) {
    ContractResult contractResult = tx.getContractResult();
    contractService.saveContractExecuteResult(tx.getHash(), contractResult);
    CreateContractData txData = tx.getTxData();
    byte[] contractAddress = txData.getContractAddress();
    byte[] sender = txData.getSender();
    String senderStr = AddressTool.getStringAddressByBytes(sender);
    String contractAddressStr = AddressTool.getStringAddressByBytes(contractAddress);
    // 移除未确认的创建合约交易
    contractTxService.removeLocalUnconfirmedCreateContractTransaction(senderStr, contractAddressStr, contractResult);
    // 执行失败的合约直接返回
    if (!contractResult.isSuccess()) {
        return Result.getSuccess();
    }
    NulsDigestData hash = tx.getHash();
    long blockHeight = tx.getBlockHeight();
    long bestBlockHeight = NulsContext.getInstance().getBestHeight();
    ContractAddressInfoPo info = new ContractAddressInfoPo();
    info.setContractAddress(contractAddress);
    info.setSender(sender);
    try {
        info.setCreateTxHash(hash.serialize());
    } catch (IOException e) {
        throw new NulsRuntimeException(e);
    }
    info.setCreateTime(tx.getTime());
    info.setBlockHeight(blockHeight);
    // byte[] stateRoot = contractResult.getStateRoot();
    boolean isNrc20Contract = contractResult.isNrc20();
    boolean acceptDirectTransfer = contractResult.isAcceptDirectTransfer();
    info.setAcceptDirectTransfer(acceptDirectTransfer);
    info.setNrc20(isNrc20Contract);
    // 获取 token tracker
    if (isNrc20Contract) {
        BlockHeader blockHeader = tx.getBlockHeader();
        byte[] newestStateRoot = blockHeader.getStateRoot();
        // NRC20 token 标准方法获取名称数据
        ProgramResult programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_NAME, null, null);
        if (programResult.isSuccess()) {
            String tokenName = programResult.getResult();
            info.setNrc20TokenName(tokenName);
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_SYMBOL, null, null);
        if (programResult.isSuccess()) {
            String symbol = programResult.getResult();
            info.setNrc20TokenSymbol(symbol);
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_DECIMALS, null, null);
        if (programResult.isSuccess()) {
            String decimals = programResult.getResult();
            if (StringUtils.isNotBlank(decimals)) {
                try {
                    info.setDecimals(new BigInteger(decimals).longValue());
                } catch (Exception e) {
                    Log.error("Get nrc20 decimals error.", e);
                // skip it
                }
            }
        }
        programResult = vmHelper.invokeViewMethod(newestStateRoot, bestBlockHeight, contractAddress, NRC20_METHOD_TOTAL_SUPPLY, null, null);
        if (programResult.isSuccess()) {
            String totalSupply = programResult.getResult();
            if (StringUtils.isNotBlank(totalSupply)) {
                try {
                    info.setTotalSupply(new BigInteger(totalSupply));
                } catch (Exception e) {
                    Log.error("Get nrc20 totalSupply error.", e);
                // skip it
                }
            }
        }
        // 刷新创建者的token余额
        vmHelper.refreshTokenBalance(newestStateRoot, info, senderStr, contractAddressStr);
        // 处理合约事件
        vmHelper.dealEvents(newestStateRoot, tx, contractResult, info);
    }
    Result result = contractAddressStorageService.saveContractAddress(contractAddress, info);
    return result;
}
Also used : ContractResult(io.nuls.contract.dto.ContractResult) ProgramResult(io.nuls.contract.vm.program.ProgramResult) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) ContractResult(io.nuls.contract.dto.ContractResult) ValidateResult(io.nuls.kernel.validate.ValidateResult) ProgramResult(io.nuls.contract.vm.program.ProgramResult) Result(io.nuls.kernel.model.Result) ContractAddressInfoPo(io.nuls.contract.storage.po.ContractAddressInfoPo) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) NulsDigestData(io.nuls.kernel.model.NulsDigestData) BigInteger(java.math.BigInteger) BlockHeader(io.nuls.kernel.model.BlockHeader)

Aggregations

ContractResult (io.nuls.contract.dto.ContractResult)18 ValidateResult (io.nuls.kernel.validate.ValidateResult)11 IOException (java.io.IOException)10 NulsException (io.nuls.kernel.exception.NulsException)7 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)5 ContractAddressInfoPo (io.nuls.contract.storage.po.ContractAddressInfoPo)5 ContractTokenTransferInfoPo (io.nuls.contract.dto.ContractTokenTransferInfoPo)4 VarInt (io.nuls.kernel.utils.VarInt)4 ContractTransferTransaction (io.nuls.contract.entity.tx.ContractTransferTransaction)3 ContractData (io.nuls.contract.entity.txdata.ContractData)3 CreateContractData (io.nuls.contract.entity.txdata.CreateContractData)3 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)3 Result (io.nuls.kernel.model.Result)3 MeetingMember (io.nuls.consensus.poc.model.MeetingMember)2 MeetingRound (io.nuls.consensus.poc.model.MeetingRound)2 RedPunishTransaction (io.nuls.consensus.poc.protocol.tx.RedPunishTransaction)2 YellowPunishTransaction (io.nuls.consensus.poc.protocol.tx.YellowPunishTransaction)2 ContractTransfer (io.nuls.contract.dto.ContractTransfer)2 CallContractTransaction (io.nuls.contract.entity.tx.CallContractTransaction)2 CreateContractTransaction (io.nuls.contract.entity.tx.CreateContractTransaction)2