LCOV - code coverage report
Current view: top level - src/evo - specialtx_validation.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 194 226 85.8 %
Date: 2025-02-23 09:33:43 Functions: 26 26 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2017 The Dash Core developers
       2             : // Copyright (c) 2020-2022 The PIVX Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "evo/specialtx_validation.h"
       7             : 
       8             : #include "chain.h"
       9             : #include "coins.h"
      10             : #include "chainparams.h"
      11             : #include "clientversion.h"
      12             : #include "consensus/validation.h"
      13             : #include "evo/deterministicmns.h"
      14             : #include "evo/providertx.h"
      15             : #include "llmq/quorums_blockprocessor.h"
      16             : #include "messagesigner.h"
      17             : #include "primitives/transaction.h"
      18             : #include "primitives/block.h"
      19             : #include "script/standard.h"
      20             : #include "spork.h"
      21             : 
      22             : /* -- Helper static functions -- */
      23             : 
      24        1573 : static bool CheckService(const CService& addr, CValidationState& state)
      25             : {
      26        1573 :     if (!addr.IsValid()) {
      27           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
      28             :     }
      29        1573 :     if (!Params().IsRegTestNet() && !addr.IsRoutable()) {
      30           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
      31             :     }
      32             : 
      33             :     // IP port must be the default one on main-net, which cannot be used on other nets.
      34        1646 :     static int mainnetDefaultPort = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
      35        1573 :     if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
      36           2 :         if (addr.GetPort() != mainnetDefaultPort) {
      37           0 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr-port");
      38             :         }
      39        1571 :     } else if (addr.GetPort() == mainnetDefaultPort) {
      40           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr-port");
      41             :     }
      42             : 
      43             :     // !TODO: add support for IPv6 and Tor
      44        1573 :     if (!addr.IsIPv4()) {
      45           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-ipaddr");
      46             :     }
      47             : 
      48             :     return true;
      49             : }
      50             : 
      51             : template <typename Payload>
      52          87 : static bool CheckHashSig(const Payload& pl, const CKeyID& keyID, CValidationState& state)
      53             : {
      54          87 :     std::string strError;
      55          87 :     if (!CHashSigner::VerifyHash(::SerializeHash(pl), keyID, pl.vchSig, strError)) {
      56           4 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
      57             :     }
      58             :     return true;
      59             : }
      60             : 
      61             : template <typename Payload>
      62          93 : static bool CheckHashSig(const Payload& pl, const CBLSPublicKey& pubKey, CValidationState& state)
      63             : {
      64          93 :     if (!pl.sig.VerifyInsecure(pubKey, ::SerializeHash(pl))) {
      65           6 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false);
      66             :     }
      67             :     return true;
      68             : }
      69             : 
      70             : template <typename Payload>
      71         462 : static bool CheckStringSig(const Payload& pl, const CKeyID& keyID, CValidationState& state)
      72             : {
      73         462 :     std::string strError;
      74         924 :     if (!CMessageSigner::VerifyMessage(keyID, pl.vchSig, pl.MakeSignString(), strError)) {
      75           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig", false, strError);
      76             :     }
      77             :     return true;
      78             : }
      79             : 
      80             : template <typename Payload>
      81        1778 : static bool CheckInputsHash(const CTransaction& tx, const Payload& pl, CValidationState& state)
      82             : {
      83        1778 :     if (CalcTxInputsHash(tx) != pl.inputsHash) {
      84           3 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");
      85             :     }
      86             : 
      87             :     return true;
      88             : }
      89             : 
      90        1201 : static bool CheckCollateralOut(const CTxOut& out, const ProRegPL& pl, CValidationState& state, CTxDestination& collateralDestRet)
      91             : {
      92        1201 :     if (!ExtractDestination(out.scriptPubKey, collateralDestRet)) {
      93           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-dest");
      94             :     }
      95             :     // don't allow reuse of collateral key for other keys (don't allow people to put the collateral key onto an online server)
      96             :     // this check applies to internal and external collateral, but internal collaterals are not necessarely a P2PKH
      97        3602 :     if (collateralDestRet == CTxDestination(pl.keyIDOwner) ||
      98        2401 :             collateralDestRet == CTxDestination(pl.keyIDVoting)) {
      99           3 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
     100             :     }
     101             :     // check collateral amount
     102        1200 :     if (out.nValue != Params().GetConsensus().nMNCollateralAmt) {
     103           6 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-amount");
     104             :     }
     105             :     return true;
     106             : }
     107             : 
     108             : // Provider Register Payload
     109        1476 : static bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
     110             : {
     111             : 
     112        2952 :     ProRegPL pl;
     113        1476 :     if (!GetValidatedTxPayload(tx, pl, state)) {
     114             :         // pass the state returned by the function above
     115             :         return false;
     116             :     }
     117             : 
     118             :     // It's allowed to set addr to 0, which will put the MN into PoSe-banned state and require a ProUpServTx to be issues later
     119             :     // If any of both is set, it must be valid however
     120        2950 :     if (pl.addr != CService() && !CheckService(pl.addr, state)) {
     121             :         // pass the state returned by the function above
     122             :         return false;
     123             :     }
     124             : 
     125       25797 :     if (pl.collateralOutpoint.hash.IsNull()) {
     126             :         // collateral included in the proReg tx
     127         737 :         if (pl.collateralOutpoint.n >= tx.vout.size()) {
     128           0 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-index");
     129             :         }
     130        1473 :         CTxDestination collateralTxDest;
     131         737 :         if (!CheckCollateralOut(tx.vout[pl.collateralOutpoint.n], pl, state, collateralTxDest)) {
     132             :             // pass the state returned by the function above
     133           1 :             return false;
     134             :         }
     135             :         // collateral is part of this ProRegTx, so we know the collateral is owned by the issuer
     136         736 :         if (!pl.vchSig.empty()) {
     137           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-sig");
     138             :         }
     139         738 :     } else if (pindexPrev != nullptr) {
     140         466 :         assert(view != nullptr);
     141             : 
     142             :         // Referenced external collateral.
     143             :         // This is checked only when pindexPrev is not null (thus during ConnectBlock-->CheckSpecialTx),
     144             :         // because this is a contextual check: we need the updated utxo set, to verify that
     145             :         // the coin exists and it is unspent.
     146         928 :         Coin coin;
     147         466 :         if (!view->GetUTXOCoin(pl.collateralOutpoint, coin)) {
     148           6 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral");
     149             :         }
     150         926 :         CTxDestination collateralTxDest;
     151         464 :         if (!CheckCollateralOut(coin.out, pl, state, collateralTxDest)) {
     152             :             // pass the state returned by the function above
     153           4 :             return false;
     154             :         }
     155             :         // Extract key from collateral. This only works for P2PK and P2PKH collaterals and will fail for P2SH.
     156             :         // Issuer of this ProRegTx must prove ownership with this key by signing the ProRegTx
     157         462 :         const CKeyID* keyForPayloadSig = boost::get<CKeyID>(&collateralTxDest);
     158         462 :         if (!keyForPayloadSig) {
     159           0 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-pkh");
     160             :         }
     161             :         // collateral is not part of this ProRegTx, so we must verify ownership of the collateral
     162         462 :         if (!CheckStringSig(pl, *keyForPayloadSig, state)) {
     163             :             // pass the state returned by the function above
     164             :             return false;
     165             :         }
     166             :     }
     167             : 
     168        1470 :     if (!CheckInputsHash(tx, pl, state)) {
     169             :         return false;
     170             :     }
     171             : 
     172        1469 :     if (pindexPrev) {
     173        1811 :         auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
     174             :         // only allow reusing of addresses when it's for the same collateral (which replaces the old MN)
     175         912 :         if (mnList.HasUniqueProperty(pl.addr) && mnList.GetUniquePropertyMN(pl.addr)->collateralOutpoint != pl.collateralOutpoint) {
     176           9 :             return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-IP-address");
     177             :         }
     178             :         // never allow duplicate keys, even if this ProTx would replace an existing MN
     179         906 :         if (mnList.HasUniqueProperty(pl.keyIDOwner)) {
     180           6 :             return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-owner-key");
     181             :         }
     182         904 :         if (mnList.HasUniqueProperty(pl.pubKeyOperator)) {
     183           6 :             return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
     184             :         }
     185             :     }
     186             : 
     187             :     return true;
     188             : }
     189             : 
     190             : // Provider Update Service Payload
     191          98 : static bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
     192             : {
     193             : 
     194         196 :     ProUpServPL pl;
     195          98 :     if (!GetValidatedTxPayload(tx, pl, state)) {
     196             :         // pass the state returned by the function above
     197             :         return false;
     198             :     }
     199             : 
     200          98 :     if (!CheckService(pl.addr, state)) {
     201             :         // pass the state returned by the function above
     202             :         return false;
     203             :     }
     204             : 
     205          98 :     if (!CheckInputsHash(tx, pl, state)) {
     206             :         // pass the state returned by the function above
     207             :         return false;
     208             :     }
     209             : 
     210          98 :     if (pindexPrev) {
     211          60 :         auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
     212         115 :         auto mn = mnList.GetMN(pl.proTxHash);
     213          60 :         if (!mn) {
     214           2 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
     215             :         }
     216             : 
     217             :         // don't allow updating to addresses already used by other MNs
     218          74 :         if (mnList.HasUniqueProperty(pl.addr) && mnList.GetUniquePropertyMN(pl.addr)->proTxHash != pl.proTxHash) {
     219           6 :             return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
     220             :         }
     221             : 
     222          57 :         if (!pl.scriptOperatorPayout.empty()) {
     223          13 :             if (mn->nOperatorReward == 0) {
     224             :                 // don't allow to set operator reward payee in case no operatorReward was set
     225           3 :                 return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
     226             :             }
     227             :             // we may support other kinds of scripts later, but restrict it for now
     228          12 :             if (!pl.scriptOperatorPayout.IsPayToPublicKeyHash()) {
     229           0 :                 return state.DoS(10, false, REJECT_INVALID, "bad-protx-operator-payee");
     230             :             }
     231             :         }
     232             : 
     233             :         // we can only check the signature if pindexPrev != nullptr and the MN is known
     234          56 :         if (!CheckHashSig(pl, mn->pdmnState->pubKeyOperator.Get(), state)) {
     235             :             // pass the state returned by the function above
     236             :             return false;
     237             :         }
     238             :     }
     239             : 
     240             :     return true;
     241             : }
     242             : 
     243             : // Provider Update Registrar Payload
     244         148 : static bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
     245             : {
     246             : 
     247         148 :     ProUpRegPL pl;
     248         148 :     if (!GetValidatedTxPayload(tx, pl, state)) {
     249             :         // pass the state returned by the function above
     250             :         return false;
     251             :     }
     252             : 
     253         296 :     CTxDestination payoutDest;
     254         148 :     if (!ExtractDestination(pl.scriptPayout, payoutDest)) {
     255             :         // should not happen as we checked script types before
     256           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-dest");
     257             :     }
     258             : 
     259             :     // don't allow reuse of payee key for other keys
     260         148 :     if (payoutDest == CTxDestination(pl.keyIDVoting)) {
     261           0 :         return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
     262             :     }
     263             : 
     264         148 :     if (!CheckInputsHash(tx, pl, state)) {
     265             :         return false;
     266             :     }
     267             : 
     268         148 :     if (pindexPrev) {
     269          90 :         assert(view != nullptr);
     270             : 
     271             :         // ProUpReg txes are disabled when the legacy system is still active
     272             :         // !TODO: remove after complete transition to DMN
     273          90 :         if (!deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) {
     274           0 :             return state.DoS(10, false, REJECT_INVALID, "spork-21-inactive");
     275             :         }
     276             : 
     277          90 :         auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
     278         175 :         auto dmn = mnList.GetMN(pl.proTxHash);
     279          90 :         if (!dmn) {
     280           2 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
     281             :         }
     282             : 
     283             :         // don't allow reuse of payee key for owner key
     284          89 :         if (payoutDest == CTxDestination(dmn->pdmnState->keyIDOwner)) {
     285           0 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-payee-reuse");
     286             :         }
     287             : 
     288         174 :         Coin coin;
     289          89 :         if (!view->GetUTXOCoin(dmn->collateralOutpoint, coin)) {
     290             :             // this should never happen (there would be no dmn otherwise)
     291           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral");
     292             :         }
     293             : 
     294             :         // don't allow reuse of collateral key for other keys (don't allow people to put the payee key onto an online server)
     295         174 :         CTxDestination collateralTxDest;
     296          89 :         if (!ExtractDestination(coin.out.scriptPubKey, collateralTxDest)) {
     297           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-dest");
     298             :         }
     299         267 :         if (collateralTxDest == CTxDestination(dmn->pdmnState->keyIDOwner) ||
     300         178 :                 collateralTxDest == CTxDestination(pl.keyIDVoting)) {
     301           0 :             return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
     302             :         }
     303             : 
     304          89 :         if (mnList.HasUniqueProperty(pl.pubKeyOperator)) {
     305          72 :             auto otherDmn = mnList.GetUniquePropertyMN(pl.pubKeyOperator);
     306          37 :             if (pl.proTxHash != otherDmn->proTxHash) {
     307           6 :                 return state.DoS(10, false, REJECT_DUPLICATE, "bad-protx-dup-key");
     308             :             }
     309             :         }
     310             : 
     311          87 :         if (!CheckHashSig(pl, dmn->pdmnState->keyIDOwner, state)) {
     312             :             // pass the state returned by the function above
     313             :             return false;
     314             :         }
     315             : 
     316             :     }
     317             : 
     318             :     return true;
     319             : }
     320             : 
     321             : // Provider Update Revoke Payload
     322          62 : static bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
     323             : {
     324             : 
     325          62 :     ProUpRevPL pl;
     326          62 :     if (!GetValidatedTxPayload(tx, pl, state)) {
     327             :         // pass the state returned by the function above
     328             :         return false;
     329             :     }
     330             : 
     331          62 :     if (!CheckInputsHash(tx, pl, state)) {
     332             :         // pass the state returned by the function above
     333             :         return false;
     334             :     }
     335             : 
     336          62 :     if (pindexPrev) {
     337          37 :         auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
     338          72 :         auto dmn = mnList.GetMN(pl.proTxHash);
     339          37 :         if (!dmn)
     340           0 :             return state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
     341             : 
     342          37 :         if (!CheckHashSig(pl, dmn->pdmnState->pubKeyOperator.Get(), state)) {
     343             :             // pass the state returned by the function above
     344             :             return false;
     345             :         }
     346             :     }
     347             : 
     348             :     return true;
     349             : }
     350             : 
     351             : // LLMQ final commitment Payload
     352        5538 : bool VerifyLLMQCommitment(const llmq::CFinalCommitment& qfc, const CBlockIndex* pindexPrev, CValidationState& state)
     353             : {
     354        5538 :     AssertLockHeld(cs_main);
     355             : 
     356             :     // Check DKG maintenance mode
     357        5538 :     if (sporkManager.IsSporkActive(SPORK_22_LLMQ_DKG_MAINTENANCE) && !IsInitialBlockDownload()) {
     358             :         // only null commitments are accepted
     359         182 :         if (!qfc.IsNull()) {
     360           9 :             return state.DoS(50, false, REJECT_INVALID, "bad-qc-not-null-spork22");
     361             :         }
     362             :     }
     363             : 
     364             :     // Check version
     365        5535 :     if (qfc.nVersion == 0 || qfc.nVersion > llmq::CFinalCommitment::CURRENT_VERSION) {
     366           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-version");
     367             :     }
     368             : 
     369             :     // Check type
     370       11073 :     Optional<Consensus::LLMQParams> params = Params().GetConsensus().GetLLMQParams(qfc.llmqType);
     371        5535 :     if (params == nullopt) {
     372           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-type");
     373             :     }
     374             : 
     375             :     // Check sizes
     376        5535 :     if (!qfc.VerifySizes(*params)) {
     377           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-sizes");
     378             :     }
     379             : 
     380        5535 :     if (pindexPrev) {
     381             :         // Get quorum index
     382        2640 :         CBlockIndex* pindexQuorum = LookupBlockIndex(qfc.quorumHash);
     383        2640 :         if (!pindexQuorum) {
     384           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash-not-found");
     385             :         }
     386             : 
     387             :         // Check height
     388        2639 :         if (pindexQuorum->nHeight % params->dkgInterval != 0) {
     389             :             // not first block of DKG interval
     390           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-height");
     391             :         }
     392             : 
     393             :         // Check height limit
     394        2638 :         if (pindexPrev->nHeight - pindexQuorum->nHeight > params->cacheDkgInterval) {
     395           6 :             return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-height-old");
     396             :         }
     397             : 
     398        2636 :         if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
     399             :             // not part of active chain
     400           3 :             return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash-not-active-chain");
     401             :         }
     402             : 
     403             :         // Get members and check signatures (for not-null commitments)
     404        2635 :         if (!qfc.IsNull()) {
     405         546 :             std::vector<CBLSPublicKey> allkeys;
     406        1092 :             for (const auto& m : deterministicMNManager->GetAllQuorumMembers((Consensus::LLMQType)qfc.llmqType, pindexQuorum)) {
     407         819 :                 allkeys.emplace_back(m->pdmnState->pubKeyOperator.Get());
     408             :             }
     409         273 :             if (!qfc.Verify(allkeys, *params)) {
     410           0 :                 return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid");
     411             :             }
     412             :         }
     413             :     }
     414             : 
     415             :     return true;
     416             : }
     417             : 
     418        5434 : static bool CheckLLMQCommitmentTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
     419             : {
     420        5434 :     AssertLockHeld(cs_main);
     421             : 
     422       10868 :     llmq::LLMQCommPL pl;
     423        5434 :     if (!GetTxPayload(tx, pl)) {
     424           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
     425             :     }
     426             : 
     427        5434 :     if (pl.nVersion == 0 || pl.nVersion > llmq::LLMQCommPL::CURRENT_VERSION) {
     428           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-version");
     429             :     }
     430             : 
     431        5434 :     if (pindexPrev && pl.nHeight != (uint32_t)pindexPrev->nHeight + 1) {
     432           2 :         return state.DoS(100, false, REJECT_INVALID, "bad-qc-height");
     433             :     }
     434             : 
     435        5433 :     return VerifyLLMQCommitment(pl.commitment, pindexPrev, state);
     436             : }
     437             : 
     438             : // Basic non-contextual checks for all tx types
     439     1386505 : static bool CheckSpecialTxBasic(const CTransaction& tx, CValidationState& state)
     440             : {
     441     1386505 :     bool hasExtraPayload = tx.hasExtraPayload();
     442             : 
     443     1386505 :     if (tx.IsNormalType()) {
     444             :         // Type-0 txes don't have extra payload
     445     1379289 :         if (hasExtraPayload) {
     446           3 :             return state.DoS(100, error("%s: Type 0 doesn't support extra payload", __func__),
     447             :                              REJECT_INVALID, "bad-txns-type-payload");
     448             :         }
     449             :         // Normal transaction. Nothing to check
     450             :         return true;
     451             :     }
     452             : 
     453             :     // Special txes need at least version 2
     454        7221 :     if (!tx.isSaplingVersion()) {
     455           3 :         return state.DoS(100, error("%s: Type %d not supported with version %d", __func__, tx.nType, tx.nVersion),
     456             :                          REJECT_INVALID, "bad-txns-type-version");
     457             :     }
     458             : 
     459             :     // Cannot be coinbase/coinstake tx
     460        7220 :     if (tx.IsCoinBase() || tx.IsCoinStake()) {
     461           0 :         return state.DoS(10, error("%s: Special tx is coinbase or coinstake", __func__),
     462             :                          REJECT_INVALID, "bad-txns-special-coinbase");
     463             :     }
     464             : 
     465             :     // Special txes must have a non-empty payload
     466        7220 :     if (!hasExtraPayload) {
     467           3 :         return state.DoS(100, error("%s: Special tx (type=%d) without extra payload", __func__, tx.nType),
     468             :                          REJECT_INVALID, "bad-txns-payload-empty");
     469             :     }
     470             : 
     471             :     // Size limits
     472        7219 :     if (tx.extraPayload->size() > MAX_SPECIALTX_EXTRAPAYLOAD) {
     473           3 :         return state.DoS(100, error("%s: Special tx payload oversize (%d)", __func__, tx.extraPayload->size()),
     474             :                          REJECT_INVALID, "bad-txns-payload-oversize");
     475             :     }
     476             : 
     477             :     return true;
     478             : }
     479             : 
     480             : // contextual and non-contextual per-type checks
     481             : // - pindexPrev=null: CheckBlock-->CheckSpecialTxNoContext
     482             : // - pindexPrev=chainActive.Tip: AcceptToMemoryPoolWorker-->CheckSpecialTx
     483             : // - pindexPrev=pindex->pprev: ConnectBlock-->ProcessSpecialTxsInBlock-->CheckSpecialTx
     484     1386505 : bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache* view, CValidationState& state)
     485             : {
     486     1386505 :     AssertLockHeld(cs_main);
     487             : 
     488     1386505 :     if (!CheckSpecialTxBasic(tx, state)) {
     489             :         // pass the state returned by the function above
     490             :         return false;
     491             :     }
     492     1386501 :     if (pindexPrev) {
     493             :         // reject special transactions before enforcement
     494      673886 :         if (!tx.IsNormalType() && !Params().GetConsensus().NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_V6_0)) {
     495           0 :             return state.DoS(100, error("%s: Special tx when v6 upgrade not enforced yet", __func__),
     496             :                              REJECT_INVALID, "bad-txns-v6-not-active");
     497             :         }
     498             :     }
     499             :     // per-type checks
     500     1386501 :     switch (tx.nType) {
     501             :         case CTransaction::TxType::NORMAL: {
     502             :             // nothing to check
     503             :             return true;
     504             :         }
     505        1476 :         case CTransaction::TxType::PROREG: {
     506             :             // provider-register
     507        1476 :             return CheckProRegTx(tx, pindexPrev, view, state);
     508             :         }
     509          98 :         case CTransaction::TxType::PROUPSERV: {
     510             :             // provider-update-service
     511          98 :             return CheckProUpServTx(tx, pindexPrev, state);
     512             :         }
     513         148 :         case CTransaction::TxType::PROUPREG: {
     514             :             // provider-update-registrar
     515         148 :             return CheckProUpRegTx(tx, pindexPrev, view, state);
     516             :         }
     517          62 :         case CTransaction::TxType::PROUPREV: {
     518             :             // provider-update-revoke
     519          62 :             return CheckProUpRevTx(tx, pindexPrev, state);
     520             :         }
     521        5434 :         case CTransaction::TxType::LLMQCOMM: {
     522             :             // quorum commitment
     523        5434 :             return CheckLLMQCommitmentTx(tx, pindexPrev, state);
     524             :         }
     525             :     }
     526             : 
     527           0 :     return state.DoS(10, error("%s: special tx %s with invalid type %d", __func__, tx.GetHash().ToString(), tx.nType),
     528             :                      REJECT_INVALID, "bad-tx-type");
     529             : }
     530             : 
     531      712621 : bool CheckSpecialTxNoContext(const CTransaction& tx, CValidationState& state)
     532             : {
     533      712621 :     return CheckSpecialTx(tx, nullptr, nullptr, state);
     534             : }
     535             : 
     536             : 
     537       56431 : bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, const CCoinsViewCache* view, CValidationState& state, bool fJustCheck)
     538             : {
     539       56431 :     AssertLockHeld(cs_main);
     540             : 
     541             :     // check special txes
     542      559019 :     for (const CTransactionRef& tx: block.vtx) {
     543      502593 :         if (!CheckSpecialTx(*tx, pindex->pprev, view, state)) {
     544             :             // pass the state returned by the function above
     545           5 :             return false;
     546             :         }
     547             :     }
     548             : 
     549       56426 :     if (!llmq::quorumBlockProcessor->ProcessBlock(block, pindex, state, fJustCheck)) {
     550             :         // pass the state returned by the function above
     551             :         return false;
     552             :     }
     553             : 
     554       56422 :     if (!deterministicMNManager->ProcessBlock(block, pindex, state, fJustCheck)) {
     555             :         // pass the state returned by the function above
     556          12 :         return false;
     557             :     }
     558             : 
     559             :     return true;
     560             : }
     561             : 
     562        1457 : bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex)
     563             : {
     564        1457 :     if (!deterministicMNManager->UndoBlock(block, pindex)) {
     565             :         return false;
     566             :     }
     567        1457 :     if (!llmq::quorumBlockProcessor->UndoBlock(block, pindex)) {
     568           0 :         return false;
     569             :     }
     570             :     return true;
     571             : }
     572             : 
     573        1927 : uint256 CalcTxInputsHash(const CTransaction& tx)
     574             : {
     575        1927 :     CHashWriter hw(CLIENT_VERSION, SER_GETHASH);
     576             :     // transparent inputs
     577        3955 :     for (const CTxIn& in: tx.vin) {
     578        2028 :         hw << in.prevout;
     579             :     }
     580             :     // shield inputs
     581        1927 :     if (tx.hasSaplingData()) {
     582           0 :         for (const SpendDescription& sd: tx.sapData->vShieldedSpend) {
     583           0 :             hw << sd.nullifier;
     584             :         }
     585             :     }
     586        1927 :     return hw.GetHash();
     587             : }
     588             : 
     589             : template <typename T>
     590        1784 : bool GetValidatedTxPayload(const CTransaction& tx, T& obj, CValidationState& state)
     591             : {
     592        1784 :     if (tx.nType != T::SPECIALTX_TYPE) {
     593           0 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-type");
     594             :     }
     595        1784 :     if (!GetTxPayload(tx, obj)) {
     596           3 :         return state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
     597             :     }
     598        1783 :     return obj.IsTriviallyValid(state);
     599             : }

Generated by: LCOV version 1.14