<commit_before>﻿// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <services/assetconsensus.h>
#include <validation.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <ethereum/ethereum.h>
#include <ethereum/address.h>
#include <ethereum/common.h>
#include <ethereum/commondata.h>
#include <boost/thread.hpp>
#include <services/rpc/assetrpc.h>
#include <validationinterface.h>
#include <algorithm> // std::unique
extern AssetBalanceMap mempoolMapAssetBalances;
extern ArrivalTimesMapImpl arrivalTimesMap;
extern std::unordered_set<std::string> assetAllocationConflicts;
extern CCriticalSection cs_assetallocationmempoolbalance;
extern CCriticalSection cs_assetallocationarrival;
extern CCriticalSection cs_assetallocationconflicts;
std::unique_ptr<CBlockIndexDB> pblockindexdb;
std::unique_ptr<CLockedOutpointsDB> plockedoutpointsdb;
std::unique_ptr<CEthereumTxRootsDB> pethereumtxrootsdb;
std::unique_ptr<CEthereumMintedTxDB> pethereumtxmintdb;
AssetPrevTxMap mapSenderLockedOutPoints;
AssetPrevTxMap mapAssetPrevTxSender;
std::vector<std::pair<uint256, uint32_t> > vecToRemoveFromMempool;
CCriticalSection cs_assetallocationmempoolremovetx;
extern bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0);
using namespace std;
bool FormatSyscoinErrorMessage(CValidationState& state, const std::string errorMessage, bool bErrorNotInvalid, bool bConsensus){
        if(bErrorNotInvalid){
            return state.Error(errorMessage);
        }
        else{
            return state.Invalid(bConsensus? ValidationInvalidReason::CONSENSUS: ValidationInvalidReason::TX_CONFLICT, false, REJECT_INVALID, errorMessage);
        }  
}
bool CheckSyscoinMint(const bool &ibd, const CTransaction& tx, const uint256& txHash, CValidationState& state, const bool &fJustCheck, const bool& bSanity, const bool& bMiner, const int& nHeight, const int64_t& nTime, const uint256& blockhash, AssetMap& mapAssets, AssetSupplyStatsMap &mapAssetSupplyStats, AssetAllocationMap &mapAssetAllocations, EthereumMintTxVec &vecMintKeys)
{
    // unserialize mint object from txn, check for valid
    CMintSyscoin mintSyscoin(tx);
    CAsset dbAsset;
    if(mintSyscoin.IsNull())
    {
        return FormatSyscoinErrorMessage(state, "mint-unserialize", bMiner);
    } 
    if(mintSyscoin.assetAllocationTuple.IsNull())
    {
        return FormatSyscoinErrorMessage(state, "mint-asset", bMiner);
    } 
    if(!GetAsset(mintSyscoin.assetAllocationTuple.nAsset, dbAsset)) 
    {
        return FormatSyscoinErrorMessage(state, "mint-non-existing-asset", bMiner);
    }
    
   
    
    // do this check only when not in IBD (initial block download) or litemode
    // if we are starting up and verifying the db also skip this check as fLoaded will be false until startup sequence is complete
    EthereumTxRoot txRootDB;
   
    const bool &ethTxRootShouldExist = !ibd && !fLiteMode && fLoaded && fGethSynced;
    // validate that the block passed is committed to by the tx root he also passes in, then validate the spv proof to the tx root below  
    // the cutoff to keep txroots is 120k blocks and the cutoff to get approved is 40k blocks. If we are syncing after being offline for a while it should still validate up to 120k worth of txroots
    if(!pethereumtxrootsdb || !pethereumtxrootsdb->ReadTxRoots(mintSyscoin.nBlockNumber, txRootDB)){
        if(ethTxRootShouldExist){
            // we always want to pass state.Invalid() for txroot missing errors here meaning we flag the block as invalid and dos ban the sender maybe
            // the check in contextualcheckblock that does this prevents us from getting a block that's invalid flagged as error so it won't propagate the block, but if block does arrive we should dos ban peer and invalidate the block itself from connect block
            return FormatSyscoinErrorMessage(state, "mint-txroot-missing", bMiner);
        }
    }  
    // if we checking this on block we would have already verified this in checkblock
    if(ethTxRootShouldExist){
        // time must be between 1 week and 1 hour old to be accepted
        if(nTime < txRootDB.nTimestamp) {
            return FormatSyscoinErrorMessage(state, "invalid-timestamp", bMiner);
        }
        else if((nTime - txRootDB.nTimestamp) > 604800) {
            return FormatSyscoinErrorMessage(state, "mint-blockheight-too-old", bMiner);
        } 
        
        // ensure that we wait at least 1 hour before we are allowed process this mint transaction  
        // also ensure sanity test that the current height that our node thinks Eth is on isn't less than the requested block for spv proof
        else if((nTime - txRootDB.nTimestamp) < ((bGethTestnet == true)? 600: 3600)) {
            return FormatSyscoinErrorMessage(state, "mint-insufficient-confirmations", bMiner);
        }
    }
    
     // check transaction receipt validity

    const std::vector<unsigned char> &vchReceiptParentNodes = mintSyscoin.vchReceiptParentNodes;
    dev::RLP rlpReceiptParentNodes(&vchReceiptParentNodes);

    const std::vector<unsigned char> &vchReceiptValue = mintSyscoin.vchReceiptValue;
    dev::RLP rlpReceiptValue(&vchReceiptValue);
    
    if (!rlpReceiptValue.isList()){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt", bMiner);
    }
    if (rlpReceiptValue.itemCount() != 4){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt-count", bMiner);
    } 
    const uint64_t &nStatus = rlpReceiptValue[0].toInt<uint64_t>(dev::RLP::VeryStrict);
    if (nStatus != 1){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt-status", bMiner);
    } 

     
    // check transaction spv proofs
    dev::RLP rlpTxRoot(&mintSyscoin.vchTxRoot);
    dev::RLP rlpReceiptRoot(&mintSyscoin.vchReceiptRoot);

    if(!txRootDB.vchTxRoot.empty() && rlpTxRoot.toBytes(dev::RLP::VeryStrict) != txRootDB.vchTxRoot){
        return FormatSyscoinErrorMessage(state, "mint-mismatching-txroot", bMiner);
    }

    if(!txRootDB.vchReceiptRoot.empty() && rlpReceiptRoot.toBytes(dev::RLP::VeryStrict) != txRootDB.vchReceiptRoot){
        return FormatSyscoinErrorMessage(state, "mint-mismatching-receiptroot", bMiner);
    } 
    
    
    const std::vector<unsigned char> &vchTxParentNodes = mintSyscoin.vchTxParentNodes;
    dev::RLP rlpTxParentNodes(&vchTxParentNodes);
    const std::vector<unsigned char> &vchTxValue = mintSyscoin.vchTxValue;
    dev::RLP rlpTxValue(&vchTxValue);
    const std::vector<unsigned char> &vchTxPath = mintSyscoin.vchTxPath;
    dev::RLP rlpTxPath(&vchTxPath);
    const uint32_t &nPath = rlpTxPath.toInt<uint32_t>(dev::RLP::VeryStrict);
    
    // ensure eth tx not already spent
    const std::pair<uint64_t, uint32_t> &ethKey = std::make_pair(mintSyscoin.nBlockNumber, nPath);
    if(pethereumtxmintdb->ExistsKey(ethKey)){
        return FormatSyscoinErrorMessage(state, "mint-exists", bMiner);
    } 
    // add the key to flush to db later
    vecMintKeys.emplace_back(ethKey);
    
    // verify receipt proof
    if(!VerifyProof(&vchTxPath, rlpReceiptValue, rlpReceiptParentNodes, rlpReceiptRoot)){
        return FormatSyscoinErrorMessage(state, "mint-verify-receipt-proof", bMiner);
    } 
    // verify transaction proof
    if(!VerifyProof(&vchTxPath, rlpTxValue, rlpTxParentNodes, rlpTxRoot)){
        return FormatSyscoinErrorMessage(state, "mint-verify-tx-proof", bMiner);
    } 
    if (!rlpTxValue.isList()){
        return FormatSyscoinErrorMessage(state, "mint-tx-rlp-list", bMiner);
    }
    if (rlpTxValue.itemCount() < 6){
        return FormatSyscoinErrorMessage(state, "mint-tx-itemcount", bMiner);
    }        
    if (!rlpTxValue[5].isData()){
        return FormatSyscoinErrorMessage(state, "mint-tx-array", bMiner);
    }        
    if (rlpTxValue[3].isEmpty()){
        return FormatSyscoinErrorMessage(state, "mint-tx-invalid-receiver", bMiner);
    }                       
    const dev::Address &address160 = rlpTxValue[3].toHash<dev::Address>(dev::RLP::VeryStrict);

    // ensure ERC20Manager is in the "to" field for the contract, meaning the function was called on this contract for freezing supply
    if(Params().GetConsensus().vchSYSXERC20Manager != address160.asBytes()){
        return FormatSyscoinErrorMessage(state, "mint-invalid-contract-manager", bMiner);
    }
    
    CAmount outputAmount;
    uint32_t nAsset = 0;
    uint8_t nPrecision;
    const std::vector<unsigned char> &rlpBytes = rlpTxValue[5].toBytes(dev::RLP::VeryStrict);
    CWitnessAddress witnessAddress;
    std::vector<unsigned char> vchERC20ContractAddress;
    if(!parseEthMethodInputData(Params().GetConsensus().vchSYSXBurnMethodSignature, rlpBytes, dbAsset.vchContract, outputAmount, nAsset, dbAsset.nPrecision, witnessAddress)){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-data", bMiner);
    }
    if(!fUnitTest){
        if(witnessAddress != mintSyscoin.assetAllocationTuple.witnessAddress){
            return FormatSyscoinErrorMessage(state, "mint-mismatch-witness-address", bMiner);
        }   <commit_msg>remove unused var<commit_after>﻿// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <services/assetconsensus.h>
#include <validation.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <ethereum/ethereum.h>
#include <ethereum/address.h>
#include <ethereum/common.h>
#include <ethereum/commondata.h>
#include <boost/thread.hpp>
#include <services/rpc/assetrpc.h>
#include <validationinterface.h>
#include <algorithm> // std::unique
extern AssetBalanceMap mempoolMapAssetBalances;
extern ArrivalTimesMapImpl arrivalTimesMap;
extern std::unordered_set<std::string> assetAllocationConflicts;
extern CCriticalSection cs_assetallocationmempoolbalance;
extern CCriticalSection cs_assetallocationarrival;
extern CCriticalSection cs_assetallocationconflicts;
std::unique_ptr<CBlockIndexDB> pblockindexdb;
std::unique_ptr<CLockedOutpointsDB> plockedoutpointsdb;
std::unique_ptr<CEthereumTxRootsDB> pethereumtxrootsdb;
std::unique_ptr<CEthereumMintedTxDB> pethereumtxmintdb;
AssetPrevTxMap mapSenderLockedOutPoints;
AssetPrevTxMap mapAssetPrevTxSender;
std::vector<std::pair<uint256, uint32_t> > vecToRemoveFromMempool;
CCriticalSection cs_assetallocationmempoolremovetx;
extern bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0);
using namespace std;
bool FormatSyscoinErrorMessage(CValidationState& state, const std::string errorMessage, bool bErrorNotInvalid, bool bConsensus){
        if(bErrorNotInvalid){
            return state.Error(errorMessage);
        }
        else{
            return state.Invalid(bConsensus? ValidationInvalidReason::CONSENSUS: ValidationInvalidReason::TX_CONFLICT, false, REJECT_INVALID, errorMessage);
        }  
}
bool CheckSyscoinMint(const bool &ibd, const CTransaction& tx, const uint256& txHash, CValidationState& state, const bool &fJustCheck, const bool& bSanity, const bool& bMiner, const int& nHeight, const int64_t& nTime, const uint256& blockhash, AssetMap& mapAssets, AssetSupplyStatsMap &mapAssetSupplyStats, AssetAllocationMap &mapAssetAllocations, EthereumMintTxVec &vecMintKeys)
{
    // unserialize mint object from txn, check for valid
    CMintSyscoin mintSyscoin(tx);
    CAsset dbAsset;
    if(mintSyscoin.IsNull())
    {
        return FormatSyscoinErrorMessage(state, "mint-unserialize", bMiner);
    } 
    if(mintSyscoin.assetAllocationTuple.IsNull())
    {
        return FormatSyscoinErrorMessage(state, "mint-asset", bMiner);
    } 
    if(!GetAsset(mintSyscoin.assetAllocationTuple.nAsset, dbAsset)) 
    {
        return FormatSyscoinErrorMessage(state, "mint-non-existing-asset", bMiner);
    }
    
   
    
    // do this check only when not in IBD (initial block download) or litemode
    // if we are starting up and verifying the db also skip this check as fLoaded will be false until startup sequence is complete
    EthereumTxRoot txRootDB;
   
    const bool &ethTxRootShouldExist = !ibd && !fLiteMode && fLoaded && fGethSynced;
    // validate that the block passed is committed to by the tx root he also passes in, then validate the spv proof to the tx root below  
    // the cutoff to keep txroots is 120k blocks and the cutoff to get approved is 40k blocks. If we are syncing after being offline for a while it should still validate up to 120k worth of txroots
    if(!pethereumtxrootsdb || !pethereumtxrootsdb->ReadTxRoots(mintSyscoin.nBlockNumber, txRootDB)){
        if(ethTxRootShouldExist){
            // we always want to pass state.Invalid() for txroot missing errors here meaning we flag the block as invalid and dos ban the sender maybe
            // the check in contextualcheckblock that does this prevents us from getting a block that's invalid flagged as error so it won't propagate the block, but if block does arrive we should dos ban peer and invalidate the block itself from connect block
            return FormatSyscoinErrorMessage(state, "mint-txroot-missing", bMiner);
        }
    }  
    // if we checking this on block we would have already verified this in checkblock
    if(ethTxRootShouldExist){
        // time must be between 1 week and 1 hour old to be accepted
        if(nTime < txRootDB.nTimestamp) {
            return FormatSyscoinErrorMessage(state, "invalid-timestamp", bMiner);
        }
        else if((nTime - txRootDB.nTimestamp) > 604800) {
            return FormatSyscoinErrorMessage(state, "mint-blockheight-too-old", bMiner);
        } 
        
        // ensure that we wait at least 1 hour before we are allowed process this mint transaction  
        // also ensure sanity test that the current height that our node thinks Eth is on isn't less than the requested block for spv proof
        else if((nTime - txRootDB.nTimestamp) < ((bGethTestnet == true)? 600: 3600)) {
            return FormatSyscoinErrorMessage(state, "mint-insufficient-confirmations", bMiner);
        }
    }
    
     // check transaction receipt validity

    const std::vector<unsigned char> &vchReceiptParentNodes = mintSyscoin.vchReceiptParentNodes;
    dev::RLP rlpReceiptParentNodes(&vchReceiptParentNodes);

    const std::vector<unsigned char> &vchReceiptValue = mintSyscoin.vchReceiptValue;
    dev::RLP rlpReceiptValue(&vchReceiptValue);
    
    if (!rlpReceiptValue.isList()){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt", bMiner);
    }
    if (rlpReceiptValue.itemCount() != 4){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt-count", bMiner);
    } 
    const uint64_t &nStatus = rlpReceiptValue[0].toInt<uint64_t>(dev::RLP::VeryStrict);
    if (nStatus != 1){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-receipt-status", bMiner);
    } 

     
    // check transaction spv proofs
    dev::RLP rlpTxRoot(&mintSyscoin.vchTxRoot);
    dev::RLP rlpReceiptRoot(&mintSyscoin.vchReceiptRoot);

    if(!txRootDB.vchTxRoot.empty() && rlpTxRoot.toBytes(dev::RLP::VeryStrict) != txRootDB.vchTxRoot){
        return FormatSyscoinErrorMessage(state, "mint-mismatching-txroot", bMiner);
    }

    if(!txRootDB.vchReceiptRoot.empty() && rlpReceiptRoot.toBytes(dev::RLP::VeryStrict) != txRootDB.vchReceiptRoot){
        return FormatSyscoinErrorMessage(state, "mint-mismatching-receiptroot", bMiner);
    } 
    
    
    const std::vector<unsigned char> &vchTxParentNodes = mintSyscoin.vchTxParentNodes;
    dev::RLP rlpTxParentNodes(&vchTxParentNodes);
    const std::vector<unsigned char> &vchTxValue = mintSyscoin.vchTxValue;
    dev::RLP rlpTxValue(&vchTxValue);
    const std::vector<unsigned char> &vchTxPath = mintSyscoin.vchTxPath;
    dev::RLP rlpTxPath(&vchTxPath);
    const uint32_t &nPath = rlpTxPath.toInt<uint32_t>(dev::RLP::VeryStrict);
    
    // ensure eth tx not already spent
    const std::pair<uint64_t, uint32_t> &ethKey = std::make_pair(mintSyscoin.nBlockNumber, nPath);
    if(pethereumtxmintdb->ExistsKey(ethKey)){
        return FormatSyscoinErrorMessage(state, "mint-exists", bMiner);
    } 
    // add the key to flush to db later
    vecMintKeys.emplace_back(ethKey);
    
    // verify receipt proof
    if(!VerifyProof(&vchTxPath, rlpReceiptValue, rlpReceiptParentNodes, rlpReceiptRoot)){
        return FormatSyscoinErrorMessage(state, "mint-verify-receipt-proof", bMiner);
    } 
    // verify transaction proof
    if(!VerifyProof(&vchTxPath, rlpTxValue, rlpTxParentNodes, rlpTxRoot)){
        return FormatSyscoinErrorMessage(state, "mint-verify-tx-proof", bMiner);
    } 
    if (!rlpTxValue.isList()){
        return FormatSyscoinErrorMessage(state, "mint-tx-rlp-list", bMiner);
    }
    if (rlpTxValue.itemCount() < 6){
        return FormatSyscoinErrorMessage(state, "mint-tx-itemcount", bMiner);
    }        
    if (!rlpTxValue[5].isData()){
        return FormatSyscoinErrorMessage(state, "mint-tx-array", bMiner);
    }        
    if (rlpTxValue[3].isEmpty()){
        return FormatSyscoinErrorMessage(state, "mint-tx-invalid-receiver", bMiner);
    }                       
    const dev::Address &address160 = rlpTxValue[3].toHash<dev::Address>(dev::RLP::VeryStrict);

    // ensure ERC20Manager is in the "to" field for the contract, meaning the function was called on this contract for freezing supply
    if(Params().GetConsensus().vchSYSXERC20Manager != address160.asBytes()){
        return FormatSyscoinErrorMessage(state, "mint-invalid-contract-manager", bMiner);
    }
    
    CAmount outputAmount;
    uint32_t nAsset = 0;
    const std::vector<unsigned char> &rlpBytes = rlpTxValue[5].toBytes(dev::RLP::VeryStrict);
    CWitnessAddress witnessAddress;
    std::vector<unsigned char> vchERC20ContractAddress;
    if(!parseEthMethodInputData(Params().GetConsensus().vchSYSXBurnMethodSignature, rlpBytes, dbAsset.vchContract, outputAmount, nAsset, dbAsset.nPrecision, witnessAddress)){
        return FormatSyscoinErrorMessage(state, "mint-invalid-tx-data", bMiner);
    }
    if(!fUnitTest){
        if(witnessAddress != mintSyscoin.assetAllocationTuple.witnessAddress){
            return FormatSyscoinErrorMessage(state, "mint-mismatch-witness-address", bMiner);
        }   
{'fraction_non_alphanumeric': 0.09855119472375391, 'fraction_numerical': 0.008811763433884744, 'mean_word_length': 4.142896858493189, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3199512', 'n_tokens_mistral': 6040, 'n_tokens_neox': 5656, 'n_words': 1372}