LCOV - code coverage report
Current view: top level - src/evo - providertx.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 122 143 85.3 %
Date: 2026-06-25 07:23:43 Functions: 19 19 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <evo/providertx.h>
       6             : 
       7             : #include <evo/dmn_types.h>
       8             : #include <util/std23.h>
       9             : 
      10             : #include <chainparams.h>
      11             : #include <consensus/validation.h>
      12             : #include <deploymentstatus.h>
      13             : #include <hash.h>
      14             : #include <script/standard.h>
      15             : #include <tinyformat.h>
      16             : #include <validation.h>
      17             : 
      18             : namespace ProTxVersion {
      19             : template <typename T>
      20        8922 : [[nodiscard]] uint16_t GetMaxFromDeployment(gsl::not_null<const CBlockIndex*> pindexPrev,
      21             :                                             const ChainstateManager& chainman, std::optional<bool> is_basic_override)
      22             : {
      23        8922 :     constexpr bool is_extaddr_eligible{std::is_same_v<std::decay_t<T>, CProRegTx> || std::is_same_v<std::decay_t<T>, CProUpServTx>};
      24        8922 :     return ProTxVersion::GetMax(
      25        8922 :         is_basic_override ? *is_basic_override
      26        8349 :                           : DeploymentActiveAfter(pindexPrev, chainman.GetConsensus(), Consensus::DEPLOYMENT_V19),
      27        8636 :         is_extaddr_eligible ? DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_V24) : false);
      28             : }
      29             : template uint16_t GetMaxFromDeployment<CProRegTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
      30             :                                                   const ChainstateManager& chainman,
      31             :                                                   std::optional<bool> is_basic_override);
      32             : template uint16_t GetMaxFromDeployment<CProUpServTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
      33             :                                                      const ChainstateManager& chainman,
      34             :                                                      std::optional<bool> is_basic_override);
      35             : template uint16_t GetMaxFromDeployment<CProUpRegTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
      36             :                                                     const ChainstateManager& chainman,
      37             :                                                     std::optional<bool> is_basic_override);
      38             : template uint16_t GetMaxFromDeployment<CProUpRevTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
      39             :                                                     const ChainstateManager& chainman,
      40             :                                                     std::optional<bool> is_basic_override);
      41             : } // namespace ProTxVersion
      42             : 
      43             : template <typename ProTx>
      44        7607 : bool IsNetInfoTriviallyValid(const ProTx& proTx, TxValidationState& state)
      45             : {
      46        7607 :     if (!proTx.netInfo->HasEntries(NetInfoPurpose::CORE_P2P)) {
      47             :         // Mandatory for all nodes
      48           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-empty");
      49             :     }
      50        7607 :     if (proTx.nType == MnType::Regular) {
      51             :         // Regular nodes shouldn't populate Platform-specific fields
      52        7015 :         if (proTx.netInfo->HasEntries(NetInfoPurpose::PLATFORM_HTTPS) ||
      53        7015 :             proTx.netInfo->HasEntries(NetInfoPurpose::PLATFORM_P2P)) {
      54           0 :             return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad");
      55             :         }
      56        7015 :     }
      57        7607 :     if (proTx.netInfo->CanStorePlatform() && proTx.nType == MnType::Evo) {
      58             :         // Platform fields are mandatory for EvoNodes
      59         112 :         if (!proTx.netInfo->HasEntries(NetInfoPurpose::PLATFORM_HTTPS) ||
      60         112 :             !proTx.netInfo->HasEntries(NetInfoPurpose::PLATFORM_P2P)) {
      61           0 :             return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-empty");
      62             :         }
      63         112 :     }
      64        7607 :     return true;
      65        7607 : }
      66             : 
      67        3881 : bool CProRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
      68             :                                  TxValidationState& state) const
      69             : {
      70        3881 :     if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
      71           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
      72             :     }
      73        3881 :     if (nVersion < ProTxVersion::BasicBLS && nType == MnType::Evo) {
      74           4 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-evo-version");
      75             :     }
      76        3877 :     if (!IsValidMnType(nType)) {
      77           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-type");
      78             :     }
      79        3877 :     if (nMode != 0) {
      80           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-mode");
      81             :     }
      82             : 
      83        3877 :     if (keyIDOwner.IsNull() || !pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
      84           2 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null");
      85             :     }
      86        3875 :     if (pubKeyOperator.IsLegacy() != (nVersion == ProTxVersion::LegacyBLS)) {
      87           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-pubkey");
      88             :     }
      89        3875 :     if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
      90           2 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee");
      91             :     }
      92        3873 :     if (netInfo->CanStorePlatform() != (nVersion == ProTxVersion::ExtAddr)) {
      93           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-netinfo-version");
      94             :     }
      95        3873 :     if (!netInfo->IsEmpty() && !IsNetInfoTriviallyValid(*this, state)) {
      96             :         // pass the state returned by the function above
      97           0 :         return false;
      98             :     }
      99        7868 :     for (const auto& entry : netInfo->GetEntries()) {
     100        3995 :         if (!entry.IsTriviallyValid()) {
     101           0 :             return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad");
     102             :         }
     103             :     }
     104             : 
     105        3873 :     CTxDestination payoutDest;
     106        3873 :     if (!ExtractDestination(scriptPayout, payoutDest)) {
     107             :         // should not happen as we checked script types before
     108           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest");
     109             :     }
     110             :     // don't allow reuse of payout key for other keys (don't allow people to put the payee key onto an online server)
     111        3873 :     if (payoutDest == CTxDestination(PKHash(keyIDOwner)) || payoutDest == CTxDestination(PKHash(keyIDVoting))) {
     112           2 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-reuse");
     113             :     }
     114             : 
     115        3871 :     if (nOperatorReward > 10000) {
     116           2 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-reward");
     117             :     }
     118             : 
     119        3869 :     return true;
     120        3881 : }
     121             : 
     122        2659 : std::string CProRegTx::MakeSignString() const
     123             : {
     124        2659 :     std::string s;
     125             : 
     126             :     // We only include the important stuff in the string form...
     127             : 
     128        2659 :     CTxDestination destPayout;
     129        2659 :     std::string strPayout;
     130        2659 :     if (ExtractDestination(scriptPayout, destPayout)) {
     131        2659 :         strPayout = EncodeDestination(destPayout);
     132        2659 :     } else {
     133           0 :         strPayout = HexStr(scriptPayout);
     134             :     }
     135             : 
     136        2659 :     s += strPayout + "|";
     137        2659 :     s += strprintf("%d", nOperatorReward) + "|";
     138        2659 :     s += EncodeDestination(PKHash(keyIDOwner)) + "|";
     139        2659 :     s += EncodeDestination(PKHash(keyIDVoting)) + "|";
     140             : 
     141             :     // ... and also the full hash of the payload as a protection against malleability and replays
     142        2659 :     s += ::SerializeHash(*this).ToString();
     143             : 
     144        2659 :     return s;
     145        2659 : }
     146             : 
     147        2789 : std::string CProRegTx::ToString() const
     148             : {
     149        2789 :     CTxDestination dest;
     150        2789 :     std::string payee = "unknown";
     151        2789 :     if (ExtractDestination(scriptPayout, dest)) {
     152        2789 :         payee = EncodeDestination(dest);
     153        2789 :     }
     154             : 
     155        2789 :     return strprintf("CProRegTx(nVersion=%d, nType=%d, collateralOutpoint=%s, netInfo=%s, nOperatorReward=%f, "
     156             :                      "ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s, platformNodeID=%s%s)\n",
     157        2789 :                      nVersion, std23::to_underlying(nType), collateralOutpoint.ToStringShort(), netInfo->ToString(),
     158        2789 :                      (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(),
     159        2789 :                      EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(),
     160        5578 :                      (nVersion >= ProTxVersion::ExtAddr
     161          40 :                           ? ""
     162        2749 :                           : strprintf(", platformP2PPort=%d, platformHTTPPort=%d", platformP2PPort, platformHTTPPort)));
     163        2789 : }
     164             : 
     165        3800 : bool CProUpServTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
     166             :                                     TxValidationState& state) const
     167             : {
     168        3800 :     if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
     169           2 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
     170             :     }
     171        3798 :     if (nVersion < ProTxVersion::BasicBLS && nType == MnType::Evo) {
     172           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-evo-version");
     173             :     }
     174        3798 :     if (netInfo->CanStorePlatform() != (nVersion == ProTxVersion::ExtAddr)) {
     175           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-netinfo-version");
     176             :     }
     177        3798 :     if (netInfo->IsEmpty()) {
     178           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-empty");
     179             :     }
     180        3798 :     if (!IsNetInfoTriviallyValid(*this, state)) {
     181             :         // pass the state returned by the function above
     182           0 :         return false;
     183             :     }
     184        7872 :     for (const auto& entry : netInfo->GetEntries()) {
     185        4074 :         if (!entry.IsTriviallyValid()) {
     186           0 :             return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad");
     187             :         }
     188             :     }
     189             : 
     190        3798 :     return true;
     191        3800 : }
     192             : 
     193        2897 : std::string CProUpServTx::ToString() const
     194             : {
     195        2897 :     CTxDestination dest;
     196        2897 :     std::string payee = "unknown";
     197        2897 :     if (ExtractDestination(scriptOperatorPayout, dest)) {
     198        1356 :         payee = EncodeDestination(dest);
     199        1356 :     }
     200             : 
     201        2897 :     return strprintf("CProUpServTx(nVersion=%d, nType=%d, proTxHash=%s, netInfo=%s, operatorPayoutAddress=%s, "
     202             :                      "platformNodeID=%s%s)\n",
     203        2897 :                      nVersion, std23::to_underlying(nType), proTxHash.ToString(), netInfo->ToString(), payee,
     204        2897 :                      platformNodeID.ToString(),
     205        5794 :                      (nVersion >= ProTxVersion::ExtAddr
     206          30 :                           ? ""
     207        2867 :                           : strprintf(", platformP2PPort=%d, platformHTTPPort=%d", platformP2PPort, platformHTTPPort)));
     208        2897 : }
     209             : 
     210         159 : bool CProUpRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
     211             :                                    TxValidationState& state) const
     212             : {
     213         159 :     if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
     214           2 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
     215             :     }
     216         157 :     if (nMode != 0) {
     217           0 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-mode");
     218             :     }
     219             : 
     220         157 :     if (!pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
     221           2 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-key-null");
     222             :     }
     223         155 :     if (pubKeyOperator.IsLegacy() != (nVersion == ProTxVersion::LegacyBLS)) {
     224           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-pubkey");
     225             :     }
     226         155 :     if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
     227           0 :         return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee");
     228             :     }
     229         155 :     return true;
     230         159 : }
     231             : 
     232         126 : std::string CProUpRegTx::ToString() const
     233             : {
     234         126 :     CTxDestination dest;
     235         126 :     std::string payee = "unknown";
     236         126 :     if (ExtractDestination(scriptPayout, dest)) {
     237         126 :         payee = EncodeDestination(dest);
     238         126 :     }
     239             : 
     240         126 :     return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, votingAddress=%s, payoutAddress=%s)",
     241         126 :         nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee);
     242         126 : }
     243             : 
     244         113 : bool CProUpRevTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
     245             :                                    TxValidationState& state) const
     246             : {
     247         113 :     if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
     248           2 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
     249             :     }
     250             : 
     251             :     // nReason < CProUpRevTx::REASON_NOT_SPECIFIED is always `false` since
     252             :     // nReason is unsigned and CProUpRevTx::REASON_NOT_SPECIFIED == 0
     253         111 :     if (nReason > CProUpRevTx::REASON_LAST) {
     254           2 :         return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-reason");
     255             :     }
     256         109 :     return true;
     257         113 : }
     258             : 
     259          73 : std::string CProUpRevTx::ToString() const
     260             : {
     261          73 :     return strprintf("CProUpRevTx(nVersion=%d, proTxHash=%s, nReason=%d)",
     262          73 :         nVersion, proTxHash.ToString(), nReason);
     263           0 : }

Generated by: LCOV version 1.16