LCOV - code coverage report
Current view: top level - src/rpc - evo_util.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 101 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 10 0.0 %

          Line data    Source code
       1             : // Copyright (c) 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 <rpc/evo_util.h>
       6             : 
       7             : #include <evo/deterministicmns.h>
       8             : #include <evo/providertx.h>
       9             : #include <index/txindex.h>
      10             : #include <rpc/protocol.h>
      11             : #include <rpc/request.h>
      12             : 
      13             : #include <univalue.h>
      14             : 
      15             : namespace {
      16           0 : bool IsNumeric(std::string_view input) { return input.find_first_not_of("0123456789") == std::string::npos; }
      17             : 
      18             : template <typename ProTx>
      19           0 : void ParseInput(ProTx& ptx, std::string_view field_name, const std::string& input_str, NetInfoPurpose purpose,
      20             :                 size_t idx, bool optional)
      21             : {
      22           0 :     if (input_str.empty()) {
      23           0 :         if (!optional) {
      24           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER,
      25           0 :                                strprintf("Invalid param for %s[%zu], cannot be empty", field_name, idx));
      26             :         }
      27           0 :         return; // Nothing to do
      28             :     }
      29           0 :     if (auto ret = ptx.netInfo->AddEntry(purpose, input_str); ret != NetInfoStatus::Success) {
      30           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER,
      31           0 :                            strprintf("Error setting %s[%zu] to '%s' (%s)", field_name, idx, input_str, NISToString(ret)));
      32             :     }
      33           0 : }
      34             : } // anonymous namespace
      35             : 
      36             : template <typename ProTx>
      37           0 : void ProcessNetInfoCore(ProTx& ptx, const UniValue& input, const bool optional)
      38             : {
      39           0 :     CHECK_NONFATAL(ptx.netInfo);
      40             : 
      41           0 :     if (input.isStr()) {
      42           0 :         ParseInput(ptx, /*field_name=*/"coreP2PAddrs", input.get_str(), NetInfoPurpose::CORE_P2P, /*idx=*/0, optional);
      43           0 :     } else if (input.isArray()) {
      44           0 :         const UniValue& entries = input.get_array();
      45           0 :         if (!optional && entries.empty()) {
      46           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid param for coreP2PAddrs, cannot be empty");
      47             :         }
      48           0 :         for (size_t idx{0}; idx < entries.size(); idx++) {
      49           0 :             const UniValue& entry_uv{entries[idx]};
      50           0 :             if (!entry_uv.isStr()) {
      51           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER,
      52           0 :                                    strprintf("Invalid param for coreP2PAddrs[%zu], must be string", idx));
      53             :             }
      54           0 :             ParseInput(ptx, /*field_name=*/"coreP2PAddrs", entry_uv.get_str(), NetInfoPurpose::CORE_P2P, idx,
      55             :                        /*optional=*/false);
      56           0 :         }
      57           0 :     } else {
      58           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid param for coreP2PAddrs, must be string or array");
      59             :     }
      60           0 : }
      61             : template void ProcessNetInfoCore(CProRegTx& ptx, const UniValue& input, const bool optional);
      62             : template void ProcessNetInfoCore(CProUpServTx& ptx, const UniValue& input, const bool optional);
      63             : 
      64             : template <typename ProTx>
      65           0 : void ProcessNetInfoPlatform(ProTx& ptx, const UniValue& input_p2p, const UniValue& input_http, const bool optional)
      66             : {
      67           0 :     CHECK_NONFATAL(ptx.netInfo);
      68             : 
      69           0 :     auto process_field = [&](uint16_t& maybe_target, const UniValue& input, const NetInfoPurpose purpose,
      70             :                              std::string_view field_name) {
      71           0 :         if (!input.isArray() && !input.isNum() && !input.isStr()) {
      72           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER,
      73           0 :                                strprintf("Invalid param for %s, must be array, number or string", field_name));
      74             :         }
      75             : 
      76           0 :         bool is_empty{input.isArray() ? input.get_array().empty() : input.getValStr().empty()};
      77           0 :         bool is_nonnumeric_str{input.isStr() && !IsNumeric(input.getValStr())};
      78           0 :         if (is_empty || is_nonnumeric_str || input.isArray()) {
      79           0 :             if (is_empty) {
      80           0 :                 if (!optional) {
      81             :                     // Mandatory field, cannot specify blank value
      82           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER,
      83           0 :                                        strprintf("Invalid param for %s, cannot be empty", field_name));
      84             :                 }
      85           0 :                 if (!ptx.netInfo->IsEmpty()) {
      86             :                     // Blank values are tolerable so long as no other field has been populated.
      87           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER,
      88           0 :                                        strprintf("Invalid param for %s, cannot be empty if other fields populated",
      89             :                                                  field_name));
      90             :                 }
      91           0 :             }
      92           0 :             if (!ptx.netInfo->CanStorePlatform()) {
      93             :                 //      Arrays: Expected to be address strings, if relying on platform{HTTP,P2P}Port, bail out.
      94             :                 // Empty Input: We can tolerate blank values if netInfo can store platform fields, if it cannot, we are relying
      95             :                 //              on platform{HTTP,P2P}Port, where it is mandatory even if their netInfo counterpart is optional.
      96             :                 //      String: If not parsable as port and relying on platform{HTTP,P2P}Port, bail out.
      97           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER,
      98           0 :                                    strprintf("Invalid param for %s, ProTx version only supports ports", field_name));
      99             :             }
     100           0 :             if (input.isArray()) {
     101           0 :                 const UniValue& entries = input.get_array();
     102           0 :                 for (size_t idx{0}; idx < entries.size(); idx++) {
     103           0 :                     const UniValue& entry{entries[idx]};
     104           0 :                     if (!entry.isStr() || IsNumeric(entry.get_str())) {
     105           0 :                         throw JSONRPCError(RPC_INVALID_PARAMETER,
     106           0 :                                            strprintf("Invalid param for %s[%zu], must be string", field_name, idx));
     107             :                     }
     108           0 :                     ParseInput(ptx, field_name, entry.get_str(), purpose, idx, /*optional=*/false);
     109           0 :                 }
     110           0 :             } else {
     111           0 :                 CHECK_NONFATAL(is_empty || is_nonnumeric_str);
     112           0 :                 ParseInput(ptx, field_name, input.get_str(), purpose, /*idx=*/0, /*optional=*/true);
     113             :             }
     114           0 :         } else {
     115           0 :             if (int32_t port{0};
     116           0 :                 ParseInt32(input.getValStr(), &port) && port >= 1 && port <= std::numeric_limits<uint16_t>::max()) {
     117             :                 // Valid port
     118           0 :                 if (!ptx.netInfo->CanStorePlatform()) {
     119           0 :                     maybe_target = static_cast<uint16_t>(port);
     120           0 :                     return; // Parsing complete
     121             :                 }
     122             :                 // We cannot store *only* a port number in netInfo so we need to associate it with the primary service of CORE_P2P manually
     123           0 :                 if (!ptx.netInfo->HasEntries(NetInfoPurpose::CORE_P2P)) {
     124           0 :                     throw JSONRPCError(RPC_INVALID_PARAMETER,
     125           0 :                                        strprintf("Cannot set param for %s, must specify coreP2PAddrs first", field_name));
     126             :                 }
     127           0 :                 const CService service{CNetAddr{ptx.netInfo->GetPrimary()}, static_cast<uint16_t>(port)};
     128           0 :                 CHECK_NONFATAL(service.IsValid());
     129           0 :                 ParseInput(ptx, field_name, service.ToStringAddrPort(), purpose, /*idx=*/0, /*optional=*/false);
     130           0 :             } else {
     131           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER,
     132           0 :                                    strprintf("Invalid param for %s, must be a valid port [1-65535]", field_name));
     133             :             }
     134             :         }
     135           0 :     };
     136           0 :     process_field(ptx.platformP2PPort, input_p2p, NetInfoPurpose::PLATFORM_P2P, "platformP2PAddrs");
     137           0 :     process_field(ptx.platformHTTPPort, input_http, NetInfoPurpose::PLATFORM_HTTPS, "platformHTTPSAddrs");
     138           0 : }
     139             : template void ProcessNetInfoPlatform(CProRegTx& ptx, const UniValue& input_p2p, const UniValue& input_http, const bool optional);
     140             : template void ProcessNetInfoPlatform(CProUpServTx& ptx, const UniValue& input_p2p, const UniValue& input_http, const bool optional);
     141             : 
     142             : 
     143           0 : UniValue CDeterministicMN::ToJson() const
     144             : {
     145           0 :     UniValue obj(UniValue::VOBJ);
     146           0 :     obj.pushKV("type", std::string(GetMnType(nType).description));
     147           0 :     obj.pushKV("proTxHash", proTxHash.ToString());
     148           0 :     obj.pushKV("collateralHash", collateralOutpoint.hash.ToString());
     149           0 :     obj.pushKV("collateralIndex", collateralOutpoint.n);
     150             : 
     151           0 :     if (g_txindex) {
     152           0 :         CTransactionRef collateralTx;
     153           0 :         uint256 nBlockHash;
     154           0 :         g_txindex->FindTx(collateralOutpoint.hash, nBlockHash, collateralTx);
     155           0 :         if (collateralTx) {
     156           0 :             CTxDestination dest;
     157           0 :             if (ExtractDestination(collateralTx->vout[collateralOutpoint.n].scriptPubKey, dest)) {
     158           0 :                 obj.pushKV("collateralAddress", EncodeDestination(dest));
     159           0 :             }
     160           0 :         }
     161           0 :     }
     162             : 
     163           0 :     obj.pushKV("operatorReward", (double)nOperatorReward / 100);
     164           0 :     obj.pushKV("state", pdmnState->ToJson(nType));
     165           0 :     return obj;
     166           0 : }

Generated by: LCOV version 1.16